/* neopixel_clock.c   */

// Arduino UNO R3
// AVR_ATmega328P
#define F_CPU 16000000UL
#include <avr/io.h>           // register names-addresses and bit names-numbers
#include <util/delay.h>

#define PIXELS 12

// 12 color palette
#define GREEN       0
#define CHARTREUSE  1
#define YELLOW      2
#define ORANGE      3
#define RED         4
#define ROSE        5
#define MAGENTA     6
#define VIOLET      7
#define BLUE        8
#define AZURE       9
#define CYAN        10
#define SPRING      11
#define BLACK       12

/* NeoPixel connections              */
/* Redefine if other pins are used   */
#define NEOPIXEL_pin PD6
#define NEOPIXEL_DDR DDRD
#define NEOPIXEL_PIN PIND
#define NEOPIXEL_PORT PORTD

void init_NeoPixel( void );
void sendBit( unsigned char bitVal );
void sendPixel( unsigned char * ptr );
void setPixelPalettColor( unsigned char *, unsigned char );


unsigned char OnePixel[3] = { 0x00, 0x00, 0x00 }; // grb-color bytes for one pixel

// the ClockFace array to store grb-color bytes for all pixels (12*3=36 bytes)
unsigned char ClockFace[ PIXELS*3 ];
unsigned char i, j, k;

int main()
{
    init_NeoPixel( );
    _delay_us (6);

   // clock start values
   unsigned char Sec_5 = 0; 
   unsigned char Min_5 = 0; 
   unsigned char Hrs = 0;    
   unsigned int loop_sec = 1 ;
   
    
    while(1)
      {

                           
           for(i = 0; i < PIXELS; i++ ) setPixelPalettColor( ClockFace + i*3, BLUE );  // Background color              

           setPixelPalettColor( ClockFace + Min_5 * 3 , GREEN);  // Minutes color              
           setPixelPalettColor( ClockFace + Hrs * 3 , RED);      // Hours color 
                          
           for(i = 0; i < PIXELS ; i++ ) sendPixel( ClockFace + i*3 );
           _delay_us (6); 
              
           _delay_ms(16); // full speed 200 ms

            if( (loop_sec % 5) == 0 )
            {
              setPixelPalettColor( ClockFace + Sec_5 * 3 , YELLOW); // Seconds color                            
              for(i = 0; i < PIXELS ; i++ ) sendPixel( ClockFace + i*3 );
              _delay_us (6); 
                            
              _delay_ms(16);  // actual speed should be 200 ms
               
              setPixelPalettColor( ClockFace + Min_5 * 3 , GREEN); // Minutes color              
              for(i = 0; i < PIXELS ; i++ ) sendPixel( ClockFace + i*3 );
              _delay_us (6); 

              _delay_ms(16);   // actual speed should be 200 ms           
            }
            else _delay_ms(32);  // actual speed should be 400 ms

           setPixelPalettColor( ClockFace + Min_5 * 3 , GREEN); // Minutes color                               
           setPixelPalettColor( ClockFace + Hrs * 3 , RED);     // Hours color             
           for(i = 0; i < PIXELS ; i++ ) sendPixel( ClockFace + i*3 );
           _delay_us (6);

           _delay_ms(16);   // actual speed should be 200 ms

           if( (loop_sec % 5) == 0 ) Sec_5 = ( ++ Sec_5) % 12;
           if( (loop_sec % 300) == 0 ) Min_5 = ( ++ Min_5) % 12;
           if( (loop_sec % 3600) == 0 ) Hrs = (++ Hrs) % 12;                                                                                    

           loop_sec++;
      }
 
  return 0;   // never reached
}





/* *********************************** */
/*            FUNCTIONS                */
/* *********************************** */

void init_NeoPixel( void )
{
   NEOPIXEL_DDR  |=  ( 1 << NEOPIXEL_pin );   // Neopixel pin "1" is output     
   NEOPIXEL_PORT &= ~( 1 << NEOPIXEL_pin );   // Neopixel pin "0" off
}


/*
   NeoPixel bit timing information. Processor f_clk = 16 MHz T = 62,5 ns.
         ______
   "0": |      |______________...     T0H (400 ns) 07 Cycles, T0L (900 ns) 15 Cycles
         ______________
   "1": |              |_________...  T1H (900 ns) 15 Cycles, T1L (600 ns) 10 Cycles

*/

// TLD 450 - 5000 ns    interbit gap 
// TLL > 6000 ns, 6 us  to latch (long delay)


inline void sendBit( unsigned char bitVal ) 
{
    if (  bitVal != 0 )    // bit is 1 
        {
          asm volatile
            (
               "sbi %[port], %[bitnr] \n\t"   // output bit set port  
               "nop \n\t"                     // T1H +13 NOP total 900 ns
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "cbi %[port], %[bitnr] \n\t"   // output bit Clear port    
               "nop \n\t"                     // T1L +8 NOP total 600 ns
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"  
                    ::
               [port]    "I" (_SFR_IO_ADDR(NEOPIXEL_PORT )),
               [bitnr]   "I" (NEOPIXEL_pin)
            );                                  
        }

    else                // bit is 0
        {
          asm volatile 
            (
               "sbi %[port], %[bitnr] \n\t"   // output bit set port   
               "nop \n\t"                     // T0H +4 NOP total 400 ns - this is critical
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "cbi %[port], %[bitnr] \n\t"   // output bit Clear port     
               "nop \n\t"                     // T0L +13 NOP total 900 ns
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
               "nop \n\t"
                    ::
               [port]    "I" (_SFR_IO_ADDR(NEOPIXEL_PORT )),
               [bitnr]   "I" (NEOPIXEL_pin)
            ); 
        }   
}  



inline void sendPixel( unsigned char * ptr )
{
   unsigned char b, c, color;

   //  send pixel 3*8=24 bits. Byte order green 0, red 1, blue 2.
   for ( c = 0; c < 3 ; c ++, ptr++ )
    {   
      // send next byte
      color = * ptr;
       
      // send 8 bits  highest-to-lowest order
      for( b = 0; b < 8; b++)
        {
           // send one bit
           sendBit(color & 0x80);
           color <<= 1;
        }
  
    }   
}


void setPixelPalettColor( unsigned char * ptr, unsigned char palettcolor )
{
    // MAX colorvalue is 255 but here reduced to 25 to get lower current consumption
    switch ( palettcolor )
      {         case GREEN:
            * ptr = 255;     // max 255 green 
            *(ptr+1) = 0;   // 0 red
            *(ptr+2) = 0;   // 0 blue
            break;

        case CHARTREUSE:
            * ptr = 255;     // max 255 green
            *(ptr+1) = 127;  // 127 red
            *(ptr+2) = 0;   // 0 blue
            break;
            
        case YELLOW:
            * ptr = 255;     // max 255 green
            *(ptr+1) = 255;  // max 255 red
            *(ptr+2) = 0;   // 0 blue
            break;

        case ORANGE:
            * ptr = 127;     // 127 green
            *(ptr+1) = 255;  // max 255 red
            *(ptr+2) = 0;   // 0 blue
            break;

        case RED:
            * ptr = 0;      // 0 green
            *(ptr+1) = 255;  // max 255 red
            *(ptr+2) = 0;   // 0 blue
            break;

        case ROSE:
            * ptr = 0;      // 0 green
            *(ptr+1) = 255;  // max 255 red
            *(ptr+2) = 127;  // 127 blue
            break;

        case MAGENTA:
            * ptr = 0;      // 0 green
            *(ptr+1) = 255;  // max 255 red
            *(ptr+2) = 255;  // max 255 blue
            break;

        case VIOLET:
            * ptr = 0;      // 0 green
            *(ptr+1) = 127;  // 127 red
            *(ptr+2) = 255;  // max 255 blue
            break;

        case BLUE:
            * ptr = 0;      // 0 green
            *(ptr+1) = 0;   // 0 red
            *(ptr+2) = 255;  // max 255 blue
            break;

        case AZURE:
            * ptr = 127;     // 127 green
            *(ptr+1) = 0;   // 0 red
            *(ptr+2) = 255;  // max 255 blue
            break;

        case CYAN:
            * ptr = 255;     // max 255 green
            *(ptr+1) = 0;   // 0 red
            *(ptr+2) = 255;  // max 255 blue
            break;

        case SPRING:
            * ptr = 25;     // max 255 green
            *(ptr+1) = 0;   // 0 red
            *(ptr+2) = 127;  // 127 blue
            break;
            
        default:  // BLACK
            * ptr = 0;      // 0 green
            *(ptr+1) = 0;   // 0 red
            *(ptr+2) = 0;   // 0 blue
      }
}


/* *********************************** */
/*            HARDWARE                 */
/* *********************************** */


/*                      Chip ATMega328                          Arduino Uno R3 stackable header
                                                                               _______
                                                               Digital:  _____/       \__  Analog:
                ______________  ______________                         -|D00 >RXD      A5|-
               |              \/              |                        -|D01 <TXD      A4|-
         Res---|01 PC6/RES' ATM328  SCL/PC5 28|-(A5)-                  -|D02           A3|-
        -(D00)-|02 PD0/RXD          SDA/PC4 27|-(A4)-                  -|D03~          A2|-
        -(D01)-|03 PD1/TXD              PC3 26|-(A3)-                  -|D04           A1|-
        -(D02)-|04 PD2/INT0             PC2 25|-(A2)-                  -|D05~          A0|-
        -(D03)-|05 PD3/INT1/PWM         PC1 24|-(A1)-            DIN -<-|D06~            | Power:      
        -(D04)-|06 PD4                  PC0 23|-(A0)-                  -|D07          Vin|-
        +5V ---|07 VCC                  GND 22|--- Gnd                  |             GND|--- GND
        Gnd ---|08 GND                 AREF 21|--- Vin                 -|D08          GND|- 
     Xtal |X|--|09 PB6/OSC1            AVCC 20|--- +5V                 -|D09~         +5V|-
    16MHz |X|--|10 PB7/OSC2         SCK/PB5 19|-(D13)-                 -|D10~       +3.3V|-
        -(D05)-|11 PD5/PWM         MISO/PB4 18|-(D12)-                 -|D11~         Res|-
  DIN -<-(D06)-|12 PD6/PWM     PWM/MOSI/PB3 17|-(D11)-                 -|D12        IOREF|-
        -(D07)-|13 PD7          PWM/SS'/PB2 16|-(D10)-                 -|D13 LED     --- |
        -(D08)-|14 PB0              PWM/PB1 15|-(D09)-                 -|GND             | 
               |______________________________|                        -|AREF            |
                                                                       -|SCL             |
                                                                       -|SDA             |
                                                                        |________________|
*/


/*       
   NeoPixel bit timing information. Processor f_clk = 16 MHz T = 62,5 ns.
         ______
   "0": |      |______________...     T0H (400 ns) 07 Cycles, T0L (900 ns) 15 Cycles
         ______________
   "1": |              |_________...  T1H (900 ns) 15 Cycles, T1L (600 ns) 10 Cycles

   TLD < 5000 ns  interbit gap 
   TLL > 6000 ns, 6 us  to latch (long delay)

           NeoPixel 12 chain                  
            _____1____     _____2____         ____12____
           |          |   |          |       |          |
    GND ---| GND  GND |---| GND  GND |- ... -| GND  GND |-
D06->-470R-| >DIN >DO |---| >DIN >DO |- ... -| >DIN >DO |-
POWER +5V -| +5V  +5V |---| +5V  +5V |- ... -| +5V  +5V |-
C 1000uF   |__________|   |__________|       |__________|

*/