/*
  ShiftRegister74HC595 - Library for simplified control of 74HC595 shift registers.
  Additional information is available at https://timodenk.com/blog/shift-register-arduino-library/
  Released into the public domain.
*/

#include <ShiftRegister74HC595.h>
#include <TimerOne.h>
#include "string.h"

#define SHIFT_REGISTER_NUM  2
#define SEGMENT_NUM    4

#define DIO_PIN    5
#define RCLK_PIN   6
#define SCLK_PIN   7


// create a global shift register object
// parameters: <number of shift registers> (data pin, clock pin, latch pin)
ShiftRegister74HC595<SHIFT_REGISTER_NUM> sr(DIO_PIN, SCLK_PIN, RCLK_PIN);
 
  
extern const uint8_t _charSet[46];
extern const uint8_t _charLeds[45];
 

uint8_t  SevenSegData[SEGMENT_NUM] = {0xFF,0xFF,0xFF,0xFF};

static int iRefreshNum = 0;
void IsrRefreshLED()
{
    uint8_t SegRegister[SHIFT_REGISTER_NUM];
    SegRegister[1] = SevenSegData[ iRefreshNum ];
    SegRegister[0] = 1<<iRefreshNum;

    sr.setAll_P( (const uint8_t *)SegRegister );

    iRefreshNum = (iRefreshNum+1)%SEGMENT_NUM;
}

void setPrintChar( int SegIdx,  char c,  uint8_t dpt )
{
    int idx;
    if( SegIdx >= SEGMENT_NUM )
    {
        return;
    }

    idx = (int)( strchr( (const char*)_charSet,   (int )c ) );
    if( idx > 45 )
    {
        idx = idx - (int)_charSet;
    }
    else
    {
        idx = 43; 
    }
    SevenSegData[ SegIdx ] =  _charLeds[idx];

    if( dpt != 0 )
    {
        SevenSegData[SegIdx] &= 0x7F;
    }
    else
    {
        SevenSegData[SegIdx] |= 0x80;
    }
}


void setPrintNum( int SegIdx,  uint8_t Num,  uint8_t dpt )
{
    if( SegIdx >= SEGMENT_NUM )
    {
        return;
    }

    Num = Num%10;
    SevenSegData[ SegIdx ] =  _charLeds[Num];

    if( dpt != 0 )
    {
        SevenSegData[SegIdx] &= 0x7F;
    }
    else
    {
        SevenSegData[SegIdx] |= 0x80;
    }
}


uint8_t setPrintStr( uint8_t* str )
{
    int i;
    int slen = 0;

    int idx = 0;

    //clear LED
    memset( SevenSegData,  0xFF, sizeof(SevenSegData)  );

    slen = strlen(  (const char*) str );
    if( slen > SEGMENT_NUM )
    {
        slen = SEGMENT_NUM;
    }

    for( i=0; i<slen; i++ )
    {
        idx = (int)( strchr( (const char*)_charSet,   (int )str[i] ) );
        if( idx > 45 )
        {
            idx = idx - (int)_charSet;
        }
        else
        {
            idx = 43; 
        }
        SevenSegData[ (slen -i-1) ] =  _charLeds[idx];
    }
    return slen;
}

uint8_t setPrintInteger( uint32_t data )
{
    uint32_t  Integer32;
    int i,idx;

    //clear LED
    memset( SevenSegData,  0xFF, sizeof(SevenSegData)  );

    Integer32 = 10;
    for(i=1; i<SEGMENT_NUM; i++)
    {
        Integer32 = Integer32*10;
    }

    Integer32 = data%Integer32;
    for( i=0; i<SEGMENT_NUM; i++ )
    {
        idx = Integer32%10; 
        SevenSegData[i] =  _charLeds[idx];
        Integer32 = Integer32/10; 
        if( Integer32 == 0 )
        {
            break;
        }
    }
    return i;
}


uint8_t setPrintFloat( float fdata )
{
    uint32_t  i,idx;
    uint32_t  Integer32, uMax;
    uint32_t  IntCnt = 0;
    uint32_t  DecCnt = 0;
    uint32_t  TotolCnt = SEGMENT_NUM;
    uint32_t  iDecimal;

    uMax = 10;
    for(i=1; i<SEGMENT_NUM; i++)
    {
        if( fdata<uMax )
        {
            break;
        }
        uMax = uMax*10;
    }

    Integer32 = fdata;
    fdata = fdata - Integer32;
    if( i >= SEGMENT_NUM )
    {
        IntCnt = SEGMENT_NUM;
        setPrintInteger( Integer32 );
        return SEGMENT_NUM;
    }
    else
    {
        IntCnt = i;
        DecCnt = SEGMENT_NUM - IntCnt;

        for(i=0; i<DecCnt; i++)
        {
            fdata = fdata*10;
        }
        iDecimal = fdata;

        for(i=DecCnt; i>0; i--)
        {
            if(iDecimal%10 != 0)
            {
                break;
            }
            iDecimal = iDecimal/10;
        }

        DecCnt = i;
    }

    TotolCnt = DecCnt+IntCnt;

    memset( SevenSegData,  0xFF, sizeof(SevenSegData)  );
    for( i=0; i<DecCnt; i++ )
    {
        idx = iDecimal%10; 
        SevenSegData[i] =  _charLeds[idx];
        iDecimal = iDecimal/10; 
    }

    for( i=0; i<IntCnt; i++ )
    {
        idx = Integer32%10; 
        SevenSegData[i+DecCnt] =  _charLeds[idx];
        Integer32 = Integer32/10; 
    }

    SevenSegData[DecCnt] &= 0x7F;

    return  TotolCnt;
}

void setup() 
{
    Timer1.attachInterrupt(IsrRefreshLED);
    Timer1.initialize(2000);

    sr.setAllLow(); // set all pins LOW
    delay(500); 
}


void loop() 
{
    setPrintChar(0, 'd', 1);
    setPrintNum( 1,  5,  1);
    setPrintChar(2, 'c', 0);
    setPrintNum( 3,  4,  0);
    delay(4000); 
    sr.setAllLow(); // set all pins LOW
    delay(1500); 

    setPrintStr( (uint8_t*)"done" );
    delay(4000); 
    sr.setAllLow(); // set all pins LOW
    delay(1500); 

    setPrintInteger( 1234 );
    delay(4000); 
    sr.setAllLow(); // set all pins LOW
    delay(1500); 

    setPrintInteger( 0 );
    delay(4000); 
    sr.setAllLow(); // set all pins LOW
    delay(1500); 

    setPrintInteger( 12 );
    delay(4000); 
    sr.setAllLow(); // set all pins LOW
    delay(1500); 

    setPrintInteger( 123 );
    delay(4000); 
    sr.setAllLow(); // set all pins LOW
    delay(1500); 


    setPrintFloat( 1.9 );
    delay(4000); 
    sr.setAllLow(); // set all pins LOW
    delay(1500); 
    
    setPrintFloat( 1.09 );
    delay(4000); 
    sr.setAllLow(); // set all pins LOW
    delay(1500); 
    
    setPrintFloat( 1.789 );
    delay(4000); 
    sr.setAllLow(); // set all pins LOW
    delay(1500); 
    
    setPrintFloat( 1.6789 );
    delay(4000); 
    sr.setAllLow(); // set all pins LOW
    delay(1500); 
    
    setPrintFloat( 0.6789 );
    delay(4000); 
    sr.setAllLow(); // set all pins LOW
    delay(1500); 
    
    setPrintFloat( 10.6789 );
    delay(4000); 
    sr.setAllLow(); // set all pins LOW
    delay(1500); 
    
    setPrintFloat( 210.6789 );
    delay(4000); 
    sr.setAllLow(); // set all pins LOW
    delay(1500); 
    
    setPrintFloat( 3210.6789 );
    delay(4000); 
    sr.setAllLow(); // set all pins LOW
    delay(1500); 

}

const uint8_t _charSet[46] = "0123456789AabCcdEeFGHhIiJLlnOoPqrStUuY-_=~* ."; // for using strchr method
const uint8_t _charLeds[45] = 
{
    0xC0, // 0
    0xF9, // 1
    0xA4, // 2
    0xB0, // 3
    0x99, // 4
    0x92, // 5
    0x82, // 6
    0xF8, // 7
    0x80, // 8
    0x90, // 9
    0x88, // A
    0xA0, // a
    0x83, // b
    0xC6, // C
    0xA7, // c
    0xA1, // d
    0x86, // E
    0x84, // e
    0x8E, // F
    0xC2, // G
    0x89, // H
    0x8B, // h
    0xF9, // I
    0xFB, // i
    0xF1, // J
    0xC7, // L
    0xCF, // l
    0xAB, // n
    0xC0, // O
    0xA3, // o
    0x8C, // P
    0x98, // q
    0xAF, // r
    0x92, // S
    0x87, // t
    0xC1, // U
    0xE3, // u
    0x91, // Y
    0xBF, // Minus -
    0xF7, // Underscore _
    0xB7, // Low =
    0xB6, //~ for Equivalent symbol
    0x9C, // *
    0xFF, // Space
    0x7F  //.
};
