/*******************************************************************************
  MPLAB Harmony Application Source File

  Company:
    Microchip Technology Inc.

  File Name:
    app_drv_spi1.c

  Summary:
    This file contains the source code for the MPLAB Harmony application.

  Description:
    This file contains the source code for the MPLAB Harmony application.  It
    implements the logic of the application's state machine and it may call
    API routines of other MPLAB Harmony modules in the system, such as drivers,
    system services, and middleware.  However, it does not call any of the
    system interfaces (such as the "Initialize" and "Tasks" functions) of any of
    the modules in the system or make any assumptions about when those functions
    are called.  That is the responsibility of the configuration-specific system
    files.
 *******************************************************************************/

// *****************************************************************************
// *****************************************************************************
// Section: Included Files
// *****************************************************************************
// *****************************************************************************

#include "app_drv_spi1.h"
#include "app_drv_usart1.h"
#include "driver/spi/drv_spi.h"
#include "system/time/sys_time.h"
#include "peripheral/port/plib_port.h"
#include "Alphabet_Fonts.h"
#include "Microchip_Logo.h"
#include <stdio.h>
#include <string.h>

// *****************************************************************************
// *****************************************************************************
// Section: Global Data Definitions
// *****************************************************************************
// *****************************************************************************
#define LCM_WIDTH 128
#define LCM_HEIGHT 64
#define FONT_WIDTH  7
#define FONT_HEIGHT 8
char  OutString[20];
char  LCM_Usart1Rx;
char  LCM_Usart2Rx;
float LCM_I2c1Temp;
char  LCM_I2c1EERPOM;
int   LCM_I2c2Accel[3];
char  Alphabet[95] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@#$%^&()[]{}_\\|;:,.`'\"<>+-*/=? ";
int  LogoX=126;
const uint8_t LCM_InitCMD[] = {
    0xAE, 0xD5, 0x80, 0xA8, 0x3F, 0xD3, 0x00, 0x40, 0x8D, 0x14, 0x20, 0x02, 0xA1,
    0xC8, 0xDA, 0x12, 0x81, 0xCF, 0xD9, 0xF1, 0xDB, 0x40, 0xA4, 0xA6, 0xAF
};
enum {
    LCM_BUS_CMD = 0,
    LCM_BUS_DAT
};

DRV_HANDLE SPI1Handle;
SYS_TIME_HANDLE SplashTimerHandle;

// *****************************************************************************
/* Application Data

  Summary:
    Holds application data

  Description:
    This structure holds the application's data.

  Remarks:
    This structure should be initialized by the APP_DRV_SPI1_Initialize function.

    Application strings and buffers are be defined outside this structure.
*/

APP_DRV_SPI1_DATA app_drv_spi1Data;

// *****************************************************************************
// *****************************************************************************
// Section: Application Callback Functions
// *****************************************************************************
// *****************************************************************************

/* TODO:  Add any necessary callback functions.
*/

// *****************************************************************************
// *****************************************************************************
// Section: Application Local Functions
// *****************************************************************************
// *****************************************************************************
void LCM_BusWrite( int bus, void *bytes, size_t counts )
{
    DRV_SPI_TRANSFER_HANDLE SPI1WriteHandle;

    if     ( bus==LCM_BUS_CMD ) SSD1306_RS_Clear();
    else if( bus==LCM_BUS_DAT ) SSD1306_RS_Set();

    DRV_SPI_WriteTransferAdd( SPI1Handle, bytes, counts, &SPI1WriteHandle );
    while( DRV_SPI_TransferStatusGet(SPI1WriteHandle)!=DRV_SPI_TRANSFER_EVENT_COMPLETE );
}

void LCM_SetCursor( uint8_t x, uint8_t y )
{
    uint8_t OUT[3] = { 0x0F & x, 0x10 + (x >> 4), 0xB0 + y };

    LCM_BusWrite( LCM_BUS_CMD, (void*)OUT, 3 );
}

void LCM_DrawBitmap( uint8_t sx, uint8_t sy, uint8_t width, uint8_t height, const unsigned char *byte )
{
    for( int y=0; y<(height/8); y++ )
    {
        LCM_SetCursor( sx, sy+y );
        LCM_BusWrite( LCM_BUS_DAT, (void*)byte, width-sx );
        byte+=width;
    }
}

void LCM_Clear( void )
{
    unsigned char LCM_Blank[1024];
    memset(LCM_Blank, 0, 1024);
    LCM_DrawBitmap(0, 0, LCM_WIDTH, LCM_HEIGHT, LCM_Blank);	
}

void LCM_DrawFont( uint8_t sx, uint8_t row, char ch )
{
    int chIdx = 0;

    while( ch != Alphabet[chIdx] ) { chIdx++; }	
    LCM_SetCursor(sx, row);
    LCM_BusWrite( LCM_BUS_DAT, (void*)(Alphabet_Fonts+(chIdx*FONT_WIDTH)), FONT_WIDTH );
}

void LCM_DrawString( uint8_t sx, uint8_t row, char *str )
{
    for( int x=0 ; x<strlen(str); x++ )
    {
        LCM_DrawFont( sx+(x*FONT_WIDTH), row, str[x] );
    }
}

// *****************************************************************************
// *****************************************************************************
// Section: Application Initialization and State Machine Functions
// *****************************************************************************
// *****************************************************************************

/*******************************************************************************
  Function:
    void APP_DRV_SPI1_Initialize ( void )

  Remarks:
    See prototype in app_drv_spi1.h.
 */

void APP_DRV_SPI1_Initialize ( void )
{
    /* Place the App state machine in its initial state. */
    app_drv_spi1Data.state = APP_DRV_SPI1_STATE_INIT;



    /* TODO: Initialize your application's state machine and other
     * parameters.
     */
}


/******************************************************************************
  Function:
    void APP_DRV_SPI1_Tasks ( void )

  Remarks:
    See prototype in app_drv_spi1.h.
 */

void APP_DRV_SPI1_Tasks ( void )
{
    switch ( app_drv_spi1Data.state )
    {
    case APP_DRV_SPI1_STATE_INIT:
        SSD1306_RESET_Clear();
        SPI1Handle = DRV_SPI_Open(DRV_SPI_INDEX_0, DRV_IO_INTENT_WRITE);
        if(SPI1Handle == DRV_HANDLE_INVALID)
        {
            app_drv_spi1Data.state = APP_DRV_SPI1_STATE_ERROR;
            break;
        }
        SSD1306_RESET_Set();

        DRV_SPI_TRANSFER_SETUP  SPI1Setup;
        SPI1Setup.baudRateInHz  = 1000000;
        SPI1Setup.clockPhase    = DRV_SPI_CLOCK_PHASE_VALID_LEADING_EDGE;
        SPI1Setup.clockPolarity = DRV_SPI_CLOCK_POLARITY_IDLE_LOW;
        SPI1Setup.dataBits      = DRV_SPI_DATA_BITS_8;
        SPI1Setup.chipSelect    = (SYS_PORT_PIN)SYS_PORT_PIN_NONE;
        SPI1Setup.csPolarity    = DRV_SPI_CS_POLARITY_ACTIVE_LOW;
        DRV_SPI_TransferSetup(SPI1Handle, &SPI1Setup);

        LCM_BusWrite( LCM_BUS_CMD, (void*)LCM_InitCMD, sizeof(LCM_InitCMD) );

        LCM_Clear();

        app_drv_spi1Data.state = APP_DRV_SPI1_STATE_SPLASH;
        break;

    case APP_DRV_SPI1_STATE_SPLASH:
        LCM_DrawBitmap( LogoX, 0, LCM_WIDTH, LCM_HEIGHT, Microchip_Logo );
        LogoX = LogoX-2;
        if( LogoX<0 )
        {
            SYS_TIME_DelayMS(1000, &SplashTimerHandle);
            app_drv_spi1Data.state = APP_DRV_SPI1_STATE_SPLASH_WAIT_COMPLETE;
        }
        break;

    case APP_DRV_SPI1_STATE_SPLASH_WAIT_COMPLETE:
        if( SYS_TIME_DelayIsComplete(SplashTimerHandle) == true )
        {
            LCM_Clear();

            SYS_TIME_DelayMS(200, &SplashTimerHandle);

            app_drv_spi1Data.state = APP_DRV_SPI1_STATE_UPDATE;
        }
        break;

    case APP_DRV_SPI1_STATE_UPDATE:
        if( SYS_TIME_DelayIsComplete(SplashTimerHandle) == false )
            break;
        SYS_TIME_DelayMS(200, &SplashTimerHandle);

        sprintf( OutString, "LCM: Hello World" );
        LCM_DrawString(0, 0, OutString);
        sprintf( OutString, "USART1 RX: %c", LCM_Usart1Rx );
        LCM_DrawString(0, 1, OutString);
        sprintf( OutString, "USART2 RX: %c", LCM_Usart2Rx );
        LCM_DrawString(0, 2, OutString);
        sprintf( OutString, "I2C1 Temp: %2.1f'C", LCM_I2c1Temp );
        LCM_DrawString(0, 3, OutString);
        sprintf( OutString, "I2C1 EEPROM: 0x%02X", LCM_I2c1EERPOM );
        LCM_DrawString(0, 4, OutString);
        sprintf( OutString, "I2C2 AccelX: %5d", LCM_I2c2Accel[0] );
        LCM_DrawString(0, 5, OutString);
        sprintf( OutString, "I2C2 AccelY: %5d", LCM_I2c2Accel[1] );
        LCM_DrawString(0, 6, OutString);
        sprintf( OutString, "I2C2 AccelZ: %5d", LCM_I2c2Accel[2] );
        LCM_DrawString(0, 7, OutString);
        break;

    case APP_DRV_SPI1_STATE_ERROR:
        USART1printf("DRV_SPI1 error!\r\n");

        app_drv_spi1Data.state = APP_DRV_SPI1_STATE_IDLE;
        break;

    case APP_DRV_SPI1_STATE_IDLE:
        break;
    }
}


/*******************************************************************************
 End of File
 */
