/*
 * ILI9341_Display_HEX.c
 *
 *  Created on: 2024/11/21
 *      Author: egaono-electronics
 */

#include "ILI9341_Display_HEX.h"

#include def_H_Periph_SPI
#include "ILI9341_SPI_Draw.h"
#include "Font_HEX_16x16_A.h"



//----------------------------------------------
// HEXの値 0x00 ～ 0xFF を
//----------------------------------------------
// 0   0   0  ... 7   7   8  ... F   F   F
//  0   1   2      E   F   0      D   E   F
//----------------------------------------------
// のように 16 x 16 dot で斜めに表示します。
//----------------------------------------------

//----------------------------------------------------------
// LCD表示 : ILI9341 : 16 x 16 HEX
//----------------------------------------------------------
// 引数;
// uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ

// uint8_t uint8_Oblong : 縦長/横長
//    0 : Lengthwise : 縦長 左
//    1 : Lengthwise : 縦長 右
//    2 : WidthwiseL : 横長 左
//    3 : WidthwiseR : 横長 右

// uint8_t uint8_Type : 表示選択
//      0 : 通常表示
//      1 : 反転表示
//      2 : 通常表示の上書き
//      3 : 反転表示の上書き

// uint32_t uint32_ColorCode : カラーコード

// uint16_t uint16_StartX : 表示開始位置X
// uint16_t uint16_StartY : 表示開始位置Y

// uint16_t uint16_Length : 表示文字数
// int16_t *pint16_aData :
//          表示文字コードが格納されているBufferのポインタ


// 戻り値;
//   -1 : 処理中
//    0 : OK終了
//    1 : NG終了
//----------------------------------------------------------
int16_t ILI9341_SPI_Display_HEX(uint8_t *puint8_JobNum,
                                uint8_t uint8_Oblong,
                                uint8_t uint8_Type,
                                uint32_t uint32_ColorCode,
                                uint16_t uint16_StartX,
                                uint16_t uint16_StartY,
                                uint16_t uint16_Length,
                                int16_t *pint16_aData)
{
  static struct sFrame_LCD STC_structFrame_LCD;

  static uint8_t STC_uint8_JobNum;  // 設定処理番号

  static uint16_t STC_uint16_Width;
  static uint16_t STC_uint16_Height;

  static uint16_t STC_uint16_SendLength;
  static uint16_t STC_uint16_Position;
  static uint16_t STC_uint16_SendCount;
  static uint16_t STC_uint16_DataSize;

  static uint16_t STC_uint16_Position_DrawBuffer;

  static int16_t STC_int16_Value_Wait_SPI_TxRx;
                                    // SPI送受信待ちの値


  int16_t int16_I;
  uint16_t uint16_I;

  int16_t int16_Return;


  switch(*puint8_JobNum)
  {
  case 0:
    //--------------------------------------------------
    // セマフォチェック
    //--------------------------------------------------
    if(GLB_int8_Semaphore_LCD != 0){
      // 他のモジュールがセマフォを使用中
      int16_Return = -1;  // 処理継続
      break;  // 処理番号維持 : 現在の処理番号をループ
    }

    GLB_int8_Semaphore_LCD = 1;  // セマフォ取得
    //--------------------------------------------------


    STC_uint8_JobNum = 0;  // 設定処理番号初期化

    STC_uint16_Position = 0;
    STC_uint16_SendCount = 0;

    STC_uint16_Position_DrawBuffer = 0;


    //----------------------------------------------
    // 表示Frame位置を構造体に設定
    //----------------------------------------------
    STC_structFrame_LCD.uint16_SC = uint16_StartX;
    STC_structFrame_LCD.uint16_EC = uint16_StartX
        + uint16_Length * def_DotWidthwise_Font16x16 - 1;

    STC_structFrame_LCD.uint16_SP = uint16_StartY;
    STC_structFrame_LCD.uint16_EP = uint16_StartY
              + def_DotLengthwise_Font16x16 - 1;


    (*puint8_JobNum)++;  // 次の処理番号に移行する。
    int16_Return = -1;   // 処理継続
    break;

  case 1:
    //----------------------------------------------------------
    // 表示Frame設定
    //----------------------------------------------------------
    // 引数;
    // uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ

    // uint16_t uint16_Oblong : 縦長/横長 選択
    //    0 : Lengthwise : 縦長 左
    //    1 : Lengthwise : 縦長 右
    //    2 : WidthwiseL : 横長 左
    //    3 : WidthwiseR : 横長 右

    // struct sFrame_LCD *pstructFrame_LCD :
    //                      表示パラメータ構造体のポインタ

    // 戻り値;
    //   -1 : 処理中
    //    0 : OK
    //    1 : NG
    //----------------------------------------------------------
    int16_Return = ILI9341_SPI_SetFrame(&STC_uint8_JobNum,
                                        (uint16_t)uint8_Oblong,
                                        &STC_structFrame_LCD);
    if(int16_Return == -1){
      // 処理中
      break;  // 処理番号維持 : 処理継続 : 現在の処理番号をループ
    }

    if(int16_Return != 0){
      //--------------------------------------------
      GLB_int8_Semaphore_LCD = 0;  // セマフォ解放
      //--------------------------------------------

      *puint8_JobNum = 0;  // 処理番号初期化
      break;  // NG終了
    }


    //----------------------------------------------------------
    // 描画Bufferに 16 x 16 Font HEXをセット
    //----------------------------------------------------------
    // 引数:
    //  int16_t int16_Type :
    //      0 : 通常表示
    //      1 : 反転表示

    //  uint16_t uint16_Length : 文字数
    //  int16_t *pint16_Char :
    //              文字コードが格納されたBufferのポインタ
    //  uint8_t *puint8_aBuffer : 描画Bufferのポインタ


    // 戻り値:
    //    なし
    //----------------------------------------------------------
    Set_DrawBuffer_Font_HEX_16x16((uint8_Type & 0x01),
                                  uint16_Length, pint16_aData,
                                  GLB_uint8_aDrawBuffer_LCD);


    //------------------------------
    // 送信データ数セット
    //------------------------------
    // 横幅のDot数を算出
    STC_uint16_Width
            = uint16_Length * def_DotWidthwise_Font16x16;
    // 表示高さをセット
    STC_uint16_Height = def_DotLengthwise_Font16x16;


    // 1回に送信するByte数を算出
    STC_uint16_DataSize = STC_uint16_Width / 8;
    if((STC_uint16_Width % 8) > 0){
      STC_uint16_DataSize++;
    }


    (*puint8_JobNum)++;  // 次の処理番号に移行する。
    int16_Return = -1;   // 処理継続
    break;

  case 2:
    //----------------------------------------------------------
    // 表示Data送信
    //----------------------------------------------------------
    if(uint8_Type < 0x02){
      // 0 : 通常表示
      // 1 : 反転表示
      for(int16_I = 0;
          int16_I < (int16_t)(STC_uint16_Width * def_RGB_byte);
          int16_I++){
        GLB_uint8_aBuffer_1Line_LCD[int16_I] = 0;
      }

      //--------------------------------------------------------
      // LCD表示用送信データ作成(カラーコード指定)  : RGB 2byte
      //--------------------------------------------------------
      // uint32_t uint32_ColorCode : カラーコード

      // uint16_t uint16_Width : 表示領域の幅
      // uint16_t uint16_Position : DrawDataの位置
      // uint8_t *puint8_aDrawData :
      //            Drawデータが格納されたBufferのポインタ
      // uint8_t *puint8_aSendData :
      //            送信データを格納するBufferのポインタ
      //--------------------------------------------------------
      MakeSendData_1Line_ColorCode_2byte(uint32_ColorCode,
                                         STC_uint16_Width,
                                         STC_uint16_Position,
                                    GLB_uint8_aDrawBuffer_LCD,
                                    GLB_uint8_aBuffer_1Line_LCD);
    }
    else{
      // 2 : 通常表示の上書き
      // 3 : 反転表示の上書き
      MakeSendData_1Line_ColorCode_2byte(uint32_ColorCode,
                                         STC_uint16_Width,
                                         STC_uint16_Position,
                                    GLB_uint8_aDrawBuffer_LCD,
                    &GLB_uint8_aWork_1Line_LCD[
                            STC_uint16_Position_DrawBuffer]);
    }

    // 送信データ数セット
    STC_uint16_SendLength = STC_uint16_Width * def_RGB_byte;


    (*puint8_JobNum)++;  // 次の処理番号に移行する。
    int16_Return = -1;   // 処理継続
    break;

  case 3:
    //----------------------------------------------------------
    // LCDに表示Dataを送信する。
    //----------------------------------------------------------
    // 引数;
    // uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ

    // int16_t int16_NSS_OnOff :
    //                  設定データ送信終了時NSS ON/OFF選択
    //    0 : 送信後 NSSをOFFにする。
    //    1 : 送信後 NSSをONのままにする。

    // uint16_t uint16_Length : 送信データ数
    // uint8_t *puint8_aData :
    //          送信データが格納されているBufferのポインタ


    // 戻り値;
    //   -1 : 処理中
    //    0 : OK
    //    1 : NG
    //----------------------------------------------------------
    if(uint8_Type < 0x02){
      // 0 : 通常表示
      // 1 : 反転表示
      int16_Return = ILI9341_SPI_SendData(&STC_uint8_JobNum,
                                          1,
                                          STC_uint16_SendLength,
                                    GLB_uint8_aBuffer_1Line_LCD);
    }
    else{
      // 2 : 通常表示の上書き
      // 3 : 反転表示の上書き
      int16_Return = ILI9341_SPI_SendData(&STC_uint8_JobNum,
                                          1,
                                          STC_uint16_SendLength,
                        &GLB_uint8_aWork_1Line_LCD[
                                STC_uint16_Position_DrawBuffer]);
    }
    if(int16_Return == -1){
      // 処理中
      break;  // 処理番号維持 : 処理継続 : 現在の処理番号をループ
    }

    if(int16_Return != 0){
      //--------------------------------------------
      GLB_int8_Semaphore_LCD = 0;  // セマフォ解放
      //--------------------------------------------

      *puint8_JobNum = 0;  // 処理番号初期化
      break;  // NG終了
    }

    // 終了判定
    STC_uint16_SendCount++;
    if(STC_uint16_SendCount < STC_uint16_Height){
      STC_uint16_Position += STC_uint16_DataSize;
                                // 次のデータ位置をセット
      STC_uint16_Position_DrawBuffer += STC_uint16_SendLength;

      (*puint8_JobNum)++;  // 次の処理番号に移行する。: case 4:
      int16_Return = -1;   // 処理継続
      break;
    }


    //--------------------------------------------
    GLB_int8_Semaphore_LCD = 0;  // セマフォ解放
    //--------------------------------------------


    *puint8_JobNum = 0;  // 処理番号初期化
    int16_Return = 0;    // OK終了
    break;

  case 4:
    if(uint8_Type < 0x02){
      // 0 : 通常表示
      // 1 : 反転表示
      for(int16_I = 0;
          int16_I < (int16_t)(STC_uint16_Width * def_RGB_byte);
          int16_I++){
        GLB_uint8_aSPI1_TxBuffer[int16_I] = 0;
      }

      //--------------------------------------------------------
      // LCD表示用送信データ作成(カラーコード指定)  : RGB 2byte
      //--------------------------------------------------------
      // 引数:
      // uint32_t uint32_ColorCode : カラーコード

      // uint16_t uint16_Width : 表示領域の幅
      // uint16_t uint16_Position : DrawDataの位置
      // uint8_t *puint8_aDrawData :
      //                Drawデータが格納されたBufferのポインタ
      // uint8_t *puint8_aSendData :
      //                送信データを格納するBufferのポインタ


      // 戻り値:
      //    なし
      //--------------------------------------------------------
      MakeSendData_1Line_ColorCode_2byte(uint32_ColorCode,
                                         STC_uint16_Width,
                                         STC_uint16_Position,
                                    GLB_uint8_aDrawBuffer_LCD,
                                    GLB_uint8_aSPI1_TxBuffer);
    }
    else{
      // 2 : 通常表示の上書き
      // 3 : 反転表示の上書き
      MakeSendData_1Line_ColorCode_2byte(uint32_ColorCode,
                                         STC_uint16_Width,
                                         STC_uint16_Position,
                                    GLB_uint8_aDrawBuffer_LCD,
                        &GLB_uint8_aWork_1Line_LCD[
                            STC_uint16_Position_DrawBuffer]);

      for(uint16_I = 0;
          uint16_I < (STC_uint16_Width * def_RGB_byte);
          uint16_I++){
        GLB_uint8_aSPI1_TxBuffer[uint16_I]
            = GLB_uint8_aWork_1Line_LCD[
                    STC_uint16_Position_DrawBuffer + uint16_I];
      }
    }


    // 送信データ数セット
    GLB_structParam_Handle_SPI1.int16_vSPI_TxNumber
                            = STC_uint16_Width * def_RGB_byte;


    (*puint8_JobNum)++;  // 次の処理番号に移行する。
    int16_Return = -1;   // 処理継続
    break;

  case 5:
    // SPI送信 : データのみ送信
    if(STC_uint16_SendCount == STC_uint16_Height - 1){
      //----------------------------------------------------------
      // SPIx  Master送受信
      //----------------------------------------------------------
      // 引数;
      // uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ

      // SPI_HandleTypeDef *pHandle_SPIx : SPI handler declaration

      // IRQn_Type DMA_Stream_IRQn_Transmit_SPIx : SPI DMA Transmit IRQn
      // IRQn_Type DMA_Stream_IRQn_Receive_SPIx : SPI DMA Receive IRQn

      // struct sParam_Handle_SPIx *pstructParam_Handle_SPIx :
      //              Handle SPI用パラメータの構造体のポインタ

      // GPIO_TypeDef *pGPIOx_SPIx_NSS : SPIx_NSS のGPIOポート
      // uint16_t uint16_GPIO_Pin_x_SPIx_NSS : SPIx_NSS のGPIOピン

      // int16_t int16_Value_Wait_SPI_TxRx : SPI送受信待ちの値

      // int16_t int16_NSS_OnOff : 送信終了時NSS ON/OFF選択
      //    0 : 送信後 NSSをOFFにする。
      //    1 : 送信後 NSSをONのままにする。


      // 戻り値;
      //   -1 : 処理中
      //    0 : OK
      //    1 : NG
      //----------------------------------------------------------
      int16_Return = SPIx_Master_TxRxByte(&STC_uint8_JobNum,
                                          &Handle_SPI1,
                                          DMA2_Stream3_IRQn,
                                          DMA2_Stream2_IRQn,
                                          &GLB_structParam_Handle_SPI1,
                                          def_GPIOx_SPI1_NSS,
                                          def_GPIO_PIN_x_SPI1_NSS,
                                          STC_int16_Value_Wait_SPI_TxRx,
                                          0);
    }
    else{
      int16_Return = SPIx_Master_TxRxByte(&STC_uint8_JobNum,
                                          &Handle_SPI1,
                                          DMA2_Stream3_IRQn,
                                          DMA2_Stream2_IRQn,
                                          &GLB_structParam_Handle_SPI1,
                                          def_GPIOx_SPI1_NSS,
                                          def_GPIO_PIN_x_SPI1_NSS,
                                          STC_int16_Value_Wait_SPI_TxRx,
                                          1);
    }
    if(int16_Return == -1){
      // 処理中
      break;  // 処理番号維持 : 処理継続 : 現在の処理番号をループ
    }

    if(int16_Return != 0){
      //--------------------------------------------
      GLB_int8_Semaphore_LCD = 0;  // セマフォ解放
      //--------------------------------------------

      *puint8_JobNum = 0;  // 処理番号初期化
      break;  // NG終了
    }

    // 終了判定
    STC_uint16_SendCount++;
    if(STC_uint16_SendCount < STC_uint16_Height){
      STC_uint16_Position += STC_uint16_DataSize;
                                    // 次のデータ位置をセット
      STC_uint16_Position_DrawBuffer += STC_uint16_SendLength;

      (*puint8_JobNum)--;  // 次の処理番号に移行する。: case 4:
      int16_Return = -1;   // 処理継続
      break;
    }


    // End : NSS OFF
    HAL_GPIO_WritePin(def_GPIOx_LCD_SPI_NSS,
                      def_GPIO_PIN_x_LCD_SPI_NSS,
                      GPIO_PIN_SET);


    //----------------------------------------------
    GLB_int8_Semaphore_LCD = 0;  // セマフォ解放
    //----------------------------------------------


    *puint8_JobNum = 0;  // 処理番号初期化
    int16_Return = 0;    // OK終了
    break;

  default:
    //----------------------------------------------
    GLB_int8_Semaphore_LCD = 0;  // セマフォ解放
    //----------------------------------------------

    *puint8_JobNum = 0;  // 処理番号初期化
    int16_Return = 1;    // NG
    break;
  }

  return(int16_Return);
}



//----------------------------------------------------------
// 描画Bufferに Font 16 x 16 HEXをセット
//----------------------------------------------------------
//  int16_t int16_Type :
//      0 : 通常表示
//      1 : 反転表示

//  uint16_t uint16_Length : 文字数
//  int16_t *uint16_Char :
//              文字コードが格納されたBufferのポインタ
//  uint8_t *puint8_aBuffer : 描画Bufferのポインタ
//----------------------------------------------------------
void Set_DrawBuffer_Font_HEX_16x16(int16_t int16_Type,
                                   uint16_t uint16_Length,
                                   int16_t *pint16_Char,
                                   uint8_t *puint8_aBuffer)
{
  uint8_t *puint8_Address_font
                = (uint8_t *)def_Font_HEX_16x16_Array;

  uint16_t uint16_AddressFont;

  uint16_t uint16_Position;

  uint16_t uint16_I;
  uint16_t uint16_J;


  for(uint16_I = 0; uint16_I < uint16_Length; uint16_I++){
    if(pint16_Char[uint16_I] >= 0){
      //------------------------------------------------
      // 通常の文字コードの場合、フォントをセットする。
      //------------------------------------------------
      uint16_AddressFont
                    = (uint16_t)pint16_Char[uint16_I] * 32;

      for(uint16_J = 0;
          uint16_J < (uint16_t)def_DotLengthwise_Font16x16;
          uint16_J++){
        uint16_Position
            = uint16_Length * 2 * uint16_J + uint16_I * 2;

        if(int16_Type == 0){
          puint8_aBuffer[uint16_Position]
            = puint8_Address_font[
                        uint16_AddressFont + uint16_J * 2];
          puint8_aBuffer[uint16_Position + 1]
            = puint8_Address_font[
                        uint16_AddressFont + uint16_J * 2 + 1];
        }
        else{
          puint8_aBuffer[uint16_Position]
            = ~puint8_Address_font[
                        uint16_AddressFont + uint16_J * 2];
          puint8_aBuffer[uint16_Position + 1]
            = ~puint8_Address_font[
                        uint16_AddressFont + uint16_J * 2 + 1];
        }
      }
    }
    else{
      //------------------------------------
      // 文字コードが -1 の場合、0クリア
      //------------------------------------
      for(uint16_J = 0;
          uint16_J < (uint16_t)def_DotLengthwise_Font16x16;
          uint16_J++){
        uint16_Position
            = uint16_Length * 2 * uint16_J + uint16_I * 2;

        if(int16_Type == 0){
          if(pint16_Char[uint16_I] == -1){
            puint8_aBuffer[uint16_Position] = 0;
            puint8_aBuffer[uint16_Position + 1] = 0;
          }
          else{
            puint8_aBuffer[uint16_Position] = 0xFF;
            puint8_aBuffer[uint16_Position + 1] = 0xFF;
          }
        }
        else{
          puint8_aBuffer[uint16_Position] = 0xFF;
          puint8_aBuffer[uint16_Position + 1] = 0xFF;
        }
      }
    }
  }
}
