/**
 * @file  sci.c
 * @brief SCIドライバ
 *
 * @version: $Id: sci.c $
 *
 * 本ソフトウェアの著作権は作成元である(株)北斗電子が所有するものとし、
 * (株)北斗電子は、以下の (1)～(3) の条件を満たす場合に限り、
 * 本ソフトウェア（本ソフトウェアを改変したものを含む。以下同じ）を
 * 使用・複製・改変・再配布（以下、利用と呼ぶ）することを無償で許諾する。
 *
 * (1) 本ソフトウェアをソースコードの形で利用する場合には、下記の著作
 *     権表示、この利用条件が、そのままの形でソースコード中に含まれて
 *     いること。
 * (2) 本ソフトウェアの一部または全てを無断で転載することを禁止するもの
 *     とする。雑誌などへ紹介・収録の場合は(株)北斗電子に連絡願います。
 * (3) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損害
 *     からも、(株)北斗電子は一切の責任を負わないものとする。
 *
 * Copyright (C) Hokuto denshi Co,Ltd. 2021
 */


/*----------------------------------------------------------------------
  インクルード
----------------------------------------------------------------------*/

#include "hal_data.h"

#include "sci.h"

/*----------------------------------------------------------------------
    関数プロトタイプ
----------------------------------------------------------------------*/

void sci_init(void);
void sci_write_char(unsigned char c);
void sci_write_uint8_hex(unsigned char c);
void sci_write_uint16_hex(unsigned short s);
void sci_write_uint32_hex(unsigned long l);
void sci_write_uint8(unsigned char num);
void sci_write_uint16(unsigned short num);
void sci_write_uint32(unsigned long num);
void sci_write_int8(char num);
void sci_write_int16(short num);
void sci_write_int32(long num);
void sci_write_str(char *str);
void sci_write_flush(void);
unsigned char sci_read_char(void);
void sci_read_buf_clear(void);
int float2str(float value, int num, char *str);

void sci9_callback (uart_callback_args_t * p_args);

/*----------------------------------------------------------------------
    グローバル変数（ファイル内）
----------------------------------------------------------------------*/

static const unsigned char hex_table_char[] = {"0123456789ABCDEF"};

/*----------------------------------------------------------------------
    グローバル変数
----------------------------------------------------------------------*/

volatile unsigned char g_sci_send_buf[SCI_SEND_BUF_SIZE];
volatile unsigned char g_sci_recv_buf[SCI_RECV_BUF_SIZE];
volatile unsigned short g_sci_send_buf_index1 = 0;
volatile unsigned short g_sci_send_buf_index2 = 0;
volatile unsigned short g_sci_recv_buf_index1 = 0;
volatile unsigned short g_sci_recv_buf_index2 = 0;
unsigned char g_sci_send_data;
unsigned char g_sci_recv_data;
volatile bool g_sci_send_flag = FLAG_CLEAR;
volatile bool g_sci_send_wait = FLAG_CLEAR;

/*----------------------------------------------------------------------
    関数定義
----------------------------------------------------------------------*/

#if (USE_SCI == 1)

void sci_init (void)
{
    //SCI初期化関数

    (void)R_SCI_UART_Open(&g_uart9_ctrl, &g_uart9_cfg);

    (void)R_SCI_UART_Read(&g_uart9_ctrl, &g_sci_recv_data, 1);

}

void sci_write_char(unsigned char c)
{
    //1文字送信関数

    //与えられた文字を表示する
    //引数
    // unsigned char c : 文字コード

    unsigned short send_buf_index;

    send_buf_index = (unsigned short)(g_sci_send_buf_index1 + 1);
    if(send_buf_index >= SCI_SEND_BUF_SIZE) send_buf_index = 0;

    if(send_buf_index == g_sci_send_buf_index2)
    {
        //バッファフル
        if(g_sci_send_wait == FLAG_CLEAR) return;
        else
        {
            //SCIが出力されて g_sci_send_buf_index2 が進むまで待つ
            while(send_buf_index == g_sci_send_buf_index2) __NOP();
        }
    }

    g_sci_send_buf_index1 = send_buf_index;
    g_sci_send_buf[g_sci_send_buf_index1] = c; //送信バッファに格納

    if(g_sci_send_flag == FLAG_CLEAR)   //送信中ではない
    {
        g_sci_send_buf_index2++;
        if(g_sci_send_buf_index2 >= SCI_SEND_BUF_SIZE) g_sci_send_buf_index2 = 0;

        g_sci_send_data = g_sci_send_buf[g_sci_send_buf_index2];

        g_sci_send_flag = FLAG_SET;
        (void)R_SCI_UART_Write(&g_uart9_ctrl, &g_sci_send_data, 1);
    }

}

void sci_write_uint8_hex(unsigned char c)
{
    //与えられた文字をhex(00-ff)2桁で表示する
    //引数
    // unsigned char c : 表示するコード(8bit)

    sci_write_char(hex_table_char[((c & 0xf0) >> 4)]);
    sci_write_char(hex_table_char[(c & 0x0f)]);
}

void sci_write_uint16_hex(unsigned short s)
{
    //与えられた文字をhex(00-ff)4桁で表示する
    //引数
    // unsigned short s : 表示するコード（16bit)

    unsigned char c;

    c = (unsigned char)((s & 0xff00) >> 8);
    sci_write_uint8_hex(c);

    c = (unsigned char)(s & 0x00ff);
    sci_write_uint8_hex(c);
}

void sci_write_uint32_hex(unsigned long l)
{
    //与えられた文字をhex(00-ff)8桁で表示する
    //引数
    // unsigned long l : 表示するコード（32bit)

    unsigned char c;

    c = (unsigned char)((l & 0xff000000) >> 24);
    sci_write_uint8_hex(c);

    c = (unsigned char)((l & 0x00ff0000) >> 16);
    sci_write_uint8_hex(c);

    c = (unsigned char)((l & 0x0000ff00) >> 8);
    sci_write_uint8_hex(c);

    c = (unsigned char)(l & 0x000000ff);
    sci_write_uint8_hex(c);
}

void sci_write_uint8(unsigned char num)
{
    //与えられた数値をで表示する
    //引数
    // unsigned char num : 表示させたい数値（符号なし）

    unsigned char n[3];

    n[0]  = num % 10;
    num  /= 10;
    n[1]  = num % 10;
    num  /= 10;
    n[2]  = num % 10;

    if(n[2] != 0)
    {
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[1] != 0)
    {
        sci_write_char(hex_table_char[n[1]]);
    }

    sci_write_char(hex_table_char[n[0]]);
}

void sci_write_uint16(unsigned short num)
{
    //与えられた数値をで表示する
    //引数
    // unsigned short num : 表示させたい数値（符号なし）

    unsigned char n[5];

    n[0]  = (unsigned char)(num % 10);
    num  /= 10;
    n[1]  = (unsigned char)(num % 10);
    num  /= 10;
    n[2]  = (unsigned char)(num % 10);
    num  /= 10;
    n[3]  = (unsigned char)(num % 10);
    num  /= 10;
    n[4]  = (unsigned char)(num % 10);

    if(n[4] != 0)
    {
        sci_write_char(hex_table_char[n[4]]);
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[3] != 0)
    {
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[2] != 0)
    {
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[1] != 0)
    {
        sci_write_char(hex_table_char[n[1]]);
    }

    sci_write_char(hex_table_char[n[0]]);
}

void sci_write_uint32(unsigned long num)
{
    //与えられた数値をで表示する
    //引数
    // unsigned short num : 表示させたい数値（符号なし）

    unsigned char n[10];

    n[0] = (unsigned char)(num % 10);
    num /= 10;
    n[1] = (unsigned char)(num % 10);
    num /= 10;
    n[2] = (unsigned char)(num % 10);
    num /= 10;
    n[3] = (unsigned char)(num % 10);
    num /= 10;
    n[4] = (unsigned char)(num % 10);
    num /= 10;
    n[5] = (unsigned char)(num % 10);
    num /= 10;
    n[6] = (unsigned char)(num % 10);
    num /= 10;
    n[7] = (unsigned char)(num % 10);
    num /= 10;
    n[8] = (unsigned char)(num % 10);
    num /= 10;
    n[9] = (unsigned char)(num % 10);

    if(n[9] != 0)
    {
        sci_write_char(hex_table_char[n[9]]);
        sci_write_char(hex_table_char[n[8]]);
        sci_write_char(hex_table_char[n[7]]);
        sci_write_char(hex_table_char[n[6]]);
        sci_write_char(hex_table_char[n[5]]);
        sci_write_char(hex_table_char[n[4]]);
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[8] != 0)
    {
        sci_write_char(hex_table_char[n[8]]);
        sci_write_char(hex_table_char[n[7]]);
        sci_write_char(hex_table_char[n[6]]);
        sci_write_char(hex_table_char[n[5]]);
        sci_write_char(hex_table_char[n[4]]);
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[7] != 0)
    {
        sci_write_char(hex_table_char[n[7]]);
        sci_write_char(hex_table_char[n[6]]);
        sci_write_char(hex_table_char[n[5]]);
        sci_write_char(hex_table_char[n[4]]);
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[6] != 0)
    {
        sci_write_char(hex_table_char[n[6]]);
        sci_write_char(hex_table_char[n[5]]);
        sci_write_char(hex_table_char[n[4]]);
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[5] != 0)
    {
        sci_write_char(hex_table_char[n[5]]);
        sci_write_char(hex_table_char[n[4]]);
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[4] != 0)
    {
        sci_write_char(hex_table_char[n[4]]);
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[3] != 0)
    {
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[2] != 0)
    {
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[1] != 0)
    {
        sci_write_char(hex_table_char[n[1]]);
    }

    sci_write_char(hex_table_char[n[0]]);
}

void sci_write_int8(char num)
{
    //与えられた数値をで表示する
    //引数
    // unsigned char num : 表示させたい数値（符号付き）

    unsigned char n[3];

    if((num & 0x80) == 0x80)
    {
        sci_write_char('-');
        num = (char)~num;
        num = (char)(num + 1);
    }

    n[0]  = (unsigned char)(num % 10);
    num  /= 10;
    n[1]  = (unsigned char)(num % 10);
    num  /= 10;
    n[2]  = (unsigned char)(num % 10);

    if(n[2] != 0)
    {
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[1] != 0)
    {
        sci_write_char(hex_table_char[n[1]]);
    }

    sci_write_char(hex_table_char[n[0]]);
}

void sci_write_int16(short num)
{
    //与えられた数値をで表示する
    //引数
    // unsigned short num : 表示させたい数値（符号付き）

    unsigned char n[5];

    if(num < 0)
    {
        sci_write_char('-');
        num = (short)(num * (-1));
    }

    n[0]  = (unsigned char)(num % 10);
    num  /= 10;
    n[1]  = (unsigned char)(num % 10);
    num  /= 10;
    n[2]  = (unsigned char)(num % 10);
    num  /= 10;
    n[3]  = (unsigned char)(num % 10);
    num  /= 10;
    n[4]  = (unsigned char)(num % 10);

    if(n[4] != 0)
    {
        sci_write_char(hex_table_char[n[4]]);
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[3] != 0)
    {
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[2] != 0)
    {
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[1] != 0)
    {
        sci_write_char(hex_table_char[n[1]]);
    }

    sci_write_char(hex_table_char[n[0]]);
}

void sci_write_int32(long num)
{
    //与えられた数値をで表示する
    //引数
    // unsigned short num : 表示させたい数値（符号付き）

    unsigned char n[10];

    if(num < 0)
    {
        sci_write_char('-');
        num *= -1;
    }

    n[0] = (unsigned char)(num % 10);
    num /= 10;
    n[1] = (unsigned char)(num % 10);
    num /= 10;
    n[2] = (unsigned char)(num % 10);
    num /= 10;
    n[3] = (unsigned char)(num % 10);
    num /= 10;
    n[4] = (unsigned char)(num % 10);
    num /= 10;
    n[5] = (unsigned char)(num % 10);
    num /= 10;
    n[6] = (unsigned char)(num % 10);
    num /= 10;
    n[7] = (unsigned char)(num % 10);
    num /= 10;
    n[8] = (unsigned char)(num % 10);
    num /= 10;
    n[9] = (unsigned char)(num % 10);

    if(n[9] != 0)
    {
        sci_write_char(hex_table_char[n[9]]);
        sci_write_char(hex_table_char[n[8]]);
        sci_write_char(hex_table_char[n[7]]);
        sci_write_char(hex_table_char[n[6]]);
        sci_write_char(hex_table_char[n[5]]);
        sci_write_char(hex_table_char[n[4]]);
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[8] != 0)
    {
        sci_write_char(hex_table_char[n[8]]);
        sci_write_char(hex_table_char[n[7]]);
        sci_write_char(hex_table_char[n[6]]);
        sci_write_char(hex_table_char[n[5]]);
        sci_write_char(hex_table_char[n[4]]);
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[7] != 0)
    {
        sci_write_char(hex_table_char[n[7]]);
        sci_write_char(hex_table_char[n[6]]);
        sci_write_char(hex_table_char[n[5]]);
        sci_write_char(hex_table_char[n[4]]);
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[6] != 0)
    {
        sci_write_char(hex_table_char[n[6]]);
        sci_write_char(hex_table_char[n[5]]);
        sci_write_char(hex_table_char[n[4]]);
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[5] != 0)
    {
        sci_write_char(hex_table_char[n[5]]);
        sci_write_char(hex_table_char[n[4]]);
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[4] != 0)
    {
        sci_write_char(hex_table_char[n[4]]);
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[3] != 0)
    {
        sci_write_char(hex_table_char[n[3]]);
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[2] != 0)
    {
        sci_write_char(hex_table_char[n[2]]);
        sci_write_char(hex_table_char[n[1]]);
    }
    else if(n[1] != 0)
    {
        sci_write_char(hex_table_char[n[1]]);
    }

    sci_write_char(hex_table_char[n[0]]);
}

void sci_write_str(char *str)
{
    //文字列表示関数
    //  引数
    //    unsigned char *str: 表示させたい文字列のポインタ（'\0'終端）

    while(*str != '\0')
    {
        if(*str == '\n')    //\nの時は\r\nに変換する
        {
            sci_write_char('\r');
        }
        sci_write_char((unsigned char)*str++);
    }
}

void sci_write_flush(void)
{
    //送信バッファのデータの出力が終わるまで待つ関数

    while(g_sci_send_buf_index1 != g_sci_send_buf_index2)
    {
        __NOP();
    }
}

unsigned char sci_read_char(void)
{
    //1文字読み出し関数
    //  戻り値
    //    unsigned char: UART受信データ
    //                   0xff(SCI_DATA_EMPTY) 受信データなし

    if(g_sci_recv_buf_index1 == g_sci_recv_buf_index2)
    {
        return SCI_DATA_EMPTY;
    }
    else
    {
        g_sci_recv_buf_index2++;
        if(g_sci_recv_buf_index2 >= SCI_RECV_BUF_SIZE) g_sci_recv_buf_index2 = 0;
        return g_sci_recv_buf[g_sci_recv_buf_index2];
    }
}

void sci_read_buf_clear(void)
{
    //読み取りバッファに格納されているデータをクリアする関数

    g_sci_recv_buf_index2 = g_sci_recv_buf_index1;
}

int float2str(float value, int num, char *str)
{
    //float文字列変換関数

    //戻り値
    // 0  : エラーなし
    // -1 : 引数エラー
    // -2 : 整数部が 2^32-1(4294967295)で表現できる数値を超えている

    //引数
    //  value : 変換元数値
    //  num   : 小数点以下桁数(0-8)
    //  *str : 戻り値ポインタ

    float f1;
    float add_f1;           //四捨五入向けに加算
    unsigned long l1, l2;
    unsigned char buf[10];

    int i, j;

    if(num > 8) return -1;
    if(num < 0) return -1;

    //符号
    if(value < 0)
    {
        f1 = value * -1.0f;
        *str++ = '-';
    }
    else
    {
        f1 = value;
    }

    //四捨五入処理
    switch(num)
    {
        case 1:
            add_f1 = 0.05f;
            break;
        case 2:
            add_f1 = 0.005f;
            break;
        case 3:
            add_f1 = 0.0005f;
            break;
        case 4:
            add_f1 = 0.00005f;
            break;
        case 5:
            add_f1 = 0.000005f;
            break;
        case 6:
            add_f1 = 0.0000005f;
            break;
        case 7:
            add_f1 = 0.00000005f;
            break;
        case 8:
            add_f1 = 0.000000005f;
            break;
        default:
            return -1;
            break;
    }
    f1 += add_f1;

    if(f1 > 4294967295) return -2;

    //整数部
    l1 = (unsigned long)f1;

    //   1234567890
    l2 = 1000000000;

    for(i=0; i<10; i++)
    {
        buf[i] = (unsigned char)(l1 / l2);

        if(i == 9) break;

        l1 -= buf[i] * l2;

        l2 /= 10;
    }

    for(i=0; i<10; i++)
    {
        if(buf[i] != 0) break;
    }

    if(i == 10)
    {
        *str++ = '0';
    }
    else
    {
        for(j=i; j<10; j++)
        {
            *str++ = (char)(buf[j] + '0');
        }
    }

    //小数部
    if(num == 0)
    {
        *str='\0';
        return 0;
    }

    switch(num)
    {
        case 1:
            l2 = 10;
            break;
        case 2:
            l2 = 100;
            break;
        case 3:
            l2 = 1000;
            break;
        case 4:
            l2 = 10000;
            break;
        case 5:
            l2 = 100000;
            break;
        case 6:
            l2 = 1000000;
            break;
        case 7:
            l2 = 10000000;
            break;
        case 8:
            l2 = 100000000;
            break;
        default:
            return -1;
            break;
    }

    f1 = f1 - (float)((unsigned long)f1);

    l1 = (unsigned long)(f1 * (float)l2);
    l2 /= 10;

    for(i=0; i<=(num-1); i++)
    {
        buf[i] = (unsigned char)(l1 / l2);

        if(i == (num-1)) break;

        l1 -= buf[i] * l2;

        l2 /= 10;
    }

    *str++ = '.';

    for(i=0; i<=(num-1); i++)
    {
        *str++ = (char)(buf[i] + '0');
    }

    *str='\0';

    return 0;
}

#else
    //SCIを使わない

void sci_init(void){ }
void sci_write_char(unsigned char c) { }
void sci_write_uint8_hex(unsigned char c){ }
void sci_write_uint16_hex(unsigned short s){ }
void sci_write_uint32_hex(unsigned long l){ }
void sci_write_uint8(unsigned char num){ }
void sci_write_uint16(unsigned short num){ }
void sci_write_uint32(unsigned long num){ }
void sci_write_int8(char num){ }
void sci_write_int16(short num){ }
void sci_write_int32(long num){ }
void sci_write_str(char *str){ }
void sci_write_flush(void){ }
unsigned char sci_read_char(void){
    return SCI_DATA_EMPTY;
}
void sci_read_buf_clear(void){ }
int float2str(float value, int num, char *str){ }

#endif

/*----------------------------------------------------------------------
    割り込み関数定義
----------------------------------------------------------------------*/

void sci9_callback (uart_callback_args_t * p_args)
{
    /* Handle the UART event */
    switch (p_args->event)
    {
        /* Received a character */
        case UART_EVENT_RX_CHAR:
        {
            g_sci_recv_data  = (unsigned char) p_args->data;
            break;
        }
        /* Receive complete */
        case UART_EVENT_RX_COMPLETE:
        {
            g_sci_recv_buf_index1++;
            if(g_sci_recv_buf_index1 >= SCI_RECV_BUF_SIZE) g_sci_recv_buf_index1 = 0;

            g_sci_recv_buf[g_sci_recv_buf_index1] = g_sci_recv_data;

            if(g_sci_recv_buf_index1 == g_sci_recv_buf_index2)      //書き込みインデックスが読み出しインデックスを超えた
            {
                g_sci_recv_buf_index2 = (unsigned short)(g_sci_recv_buf_index1 + 1);
                if(g_sci_recv_buf_index2 >= SCI_RECV_BUF_SIZE) g_sci_recv_buf_index2 = 0;
                //この時点で未読み出しのデータは捨てられるが、最新の SCI_RECV_BUF_SIZE のデータは未読み出しで有効とする
            }

            //次のデータを受信する
            (void)R_SCI_UART_Read(&g_uart9_ctrl, &g_sci_recv_data, 1);

            break;
        }
        /* Transmit complete */
        case UART_EVENT_TX_COMPLETE:
        {
            if(g_sci_send_buf_index1 == g_sci_send_buf_index2)      //送信出力が格納済みデータに追いついた（バッファが空）
            {
                g_sci_send_flag = FLAG_CLEAR;
            }
            else
            {
                g_sci_send_buf_index2++;
                if(g_sci_send_buf_index2 >= SCI_SEND_BUF_SIZE) g_sci_send_buf_index2 = 0;

                g_sci_send_data = g_sci_send_buf[g_sci_send_buf_index2];

                (void)R_SCI_UART_Write(&g_uart9_ctrl, &g_sci_send_data, 1);
            }

            break;
        }
        default:
        {
        }
    }
}

