
#define _SUPPRESS_PLIB_WARNING
#define _DISABLE_OPENADC10_CONFIGPORT_WARNING
#include <plib.h>
#include "7seg.h"

/*
  AAA
 F   B
  GGG
 E   C
  DDD
 */

#define NUM_DIGIT (LAST_DIGIT-FIRST_DIGIT+1+8)

unsigned short digits_7seg[NUM_DIGIT] = { /*-*/ SEGG,
                                          /*.*/ DP,
                                          /*/*/ SEGB|SEGE|SEGG,
                                          /*0*/ SEGA|SEGB|SEGC|SEGD|SEGE|SEGF,
                                          /*1*/ SEGB|SEGC,
                                          /*2*/ SEGA|SEGB|SEGD|SEGE|SEGG,
                                          /*3*/ SEGA|SEGB|SEGC|SEGD|SEGG,
                                          /*4*/ SEGB|SEGC|SEGF|SEGG,
                                          /*5*/ SEGA|SEGC|SEGD|SEGF|SEGG,
                                          /*6*/ SEGA|SEGC|SEGD|SEGE|SEGF|SEGG,
                                          /*7*/ SEGA|SEGB|SEGC,
                                          /*8*/ SEGA|SEGB|SEGC|SEGD|SEGE|SEGF|SEGG,
                                          /*9*/ SEGA|SEGB|SEGC|SEGD|SEGF|SEGG,
                                          /*:*/ SEGB|SEGC|SEGD, // used to form a W: "u:"
                                          /*;*/ SEGA|SEGB|SEGC|SEGE|SEGF,
                                          /*<*/ SEGE|SEGF|SEGG,
                                          /*=*/ SEGD|SEGG,
                                          /*>*/ SEGC|SEGD|SEGG,
                                          /*?*/ SEGA|SEGB|SEGE|SEGG,
                                          /*@*/ SEGA|SEGB|SEGC, // used to form a M: ";@"
                                          /*A*/ SEGA|SEGB|SEGC|SEGE|SEGF|SEGG,
                                          /*B*/ SEGC|SEGD|SEGE|SEGF|SEGG,
                                          /*C*/ SEGD|SEGE|SEGG,
                                          /*D*/ SEGB|SEGC|SEGD|SEGE|SEGG,
                                          /*E*/ SEGA|SEGD|SEGE|SEGF|SEGG,
                                          /*F*/ SEGA|SEGE|SEGF|SEGG,
                                          /*G*/ SEGA|SEGB|SEGC|SEGD|SEGF|SEGG,
                                          /*H*/ SEGC|SEGE|SEGF|SEGG,
                                          /*I*/ SEGC,
                                          /*J*/ SEGB|SEGC|SEGD,
                                          /*K*/ SEGB|SEGC|SEGE|SEGF|SEGG,
                                          /*L*/ SEGD|SEGE|SEGF,
                                          /*M*/ SEGA|SEGB|SEGC|SEGE|SEGF,
                                          /*N*/ SEGC|SEGE|SEGG,
                                          /*O*/ SEGC|SEGD|SEGE|SEGG,
                                          /*P*/ SEGA|SEGB|SEGE|SEGF|SEGG,
                                          /*Q*/ SEGA|SEGB|SEGC|SEGF|SEGG,
                                          /*R*/ SEGE|SEGG,
                                          /*S*/ SEGA|SEGC|SEGD|SEGF|SEGG,
                                          /*T*/ SEGA|SEGE|SEGF,
                                          /*U*/ SEGB|SEGC|SEGD|SEGE|SEGF,
                                          /*V*/ SEGB|SEGC|SEGF|SEGG,//SEGC|SEGD|SEGE|SEGF,
                                          /*W*/ SEGB|SEGC|SEGD|SEGE|SEGF,
                                          /*X*/ SEGB|SEGC|SEGE|SEGF|SEGG,
                                          /*Y*/ SEGB|SEGC|SEGD|SEGF|SEGG,
                                          /*Z*/ SEGA|SEGB|SEGD|SEGE|SEGG,
                                          /*[*/ SEGA|SEGD|SEGE|SEGF,
                                          /*\*/ SEGA|SEGB|SEGC, // used to form a T: "\\T"
                                          /*]*/ SEGA|SEGB|SEGC|SEGD,
                                          /*^*/ SEGA|SEGB|SEGC|SEGE|SEGF /* capital N */,
                                          SEGA, SEGB, SEGC, SEGD, SEGE, SEGF, SEGG, DP};

volatile char display[6];
volatile unsigned char colons, dps, dim_dps;
int brightness;

static unsigned char cur_digit, timer_on;//, dp_timer;
void __ISR(_TIMER_5_VECTOR,IPL4AUTO) __T5Interrupt(void) {
    ClearWDT();
    if( timer_on || brightness >= 256 ) {
        if( timer_on != 2 && ++cur_digit == 7 )
            cur_digit = 0;
        if( cur_digit < 6 ) {
            TMR5 = 0;
            PR5 = 7*brightness;
            LATB = (LATB&(0xFFFF7FFA&~DIGMASK))|( ((cur_digit&1)<<2) | ((cur_digit&2)>>1) | ((cur_digit&4)<<13) ) | (display[cur_digit] >= FIRST_DIGIT && display[cur_digit] <= LAST_DIGIT+8 ? digits_7seg[display[cur_digit]-FIRST_DIGIT] : 0) | (((dps^(timer_on != 2 ? dim_dps : 0))&(1<<cur_digit)) ? DP : 0);
            if( timer_on != 2 && (dim_dps & (1<<cur_digit)) && brightness >= 44 ) {
                PR5 = brightness;//brightness < 48 ? 48 : brightness;
                timer_on = 2;
            } else {
                timer_on = 0;
            }
        } else {
            TMR5 = 0;
            PR5 = 3*brightness;
            if( colons )
                LATB = (LATB&(0xFFFF7FFA&~DIGMASK))|( ((cur_digit&1)<<2) | ((cur_digit&2)>>1) | ((cur_digit&4)<<13) );
            else
                LATB = (LATB&(0xFFFF7FFA&~DIGMASK))|( ((7&1)<<2) | ((7&2)>>1) | ((7&4)<<13) );
            timer_on = 0;
        }
    } else {
        LATB = (LATB&(0xFFFF7FFA&~DIGMASK))|( ((7&1)<<2) | ((7&2)>>1) | ((7&4)<<13) );
        if( cur_digit < 6 ) {
            TMR5 = 0;
            PR5 = 7*(256-brightness);
        } else {
            TMR5 = 0;
            PR5 = 3*(256-brightness);
        }
        timer_on = 1;
    }
    IFS0bits.T5IF = 0;
}

__attribute__((mips16)) void setup_7seg_IOs() {
  LATB &= ~( (1<<0)|(1<<2)|(1<<3)|(1<<7)|(1<<8)|(1<<9)|(1<<10)|(1<<11)|(1<<12)|(1<<14)|(1<<15) );
//  LATB = 0;
  TRISB &= ~( (1<<0)|(1<<2)|(1<<3)|(1<<7)|(1<<8)|(1<<9)|(1<<10)|(1<<11)|(1<<12)|(1<<14)|(1<<15) );
/*
  TRISBbits.TRISB0 = 0;
  TRISBbits.TRISB2 = 0;
  TRISBbits.TRISB3 = 0;
  TRISBbits.TRISB7 = 0;
  TRISBbits.TRISB8 = 0;
  TRISBbits.TRISB9 = 0;
  TRISBbits.TRISB10 = 0;
  TRISBbits.TRISB11 = 0;
  TRISBbits.TRISB12 = 0;
  TRISBbits.TRISB14 = 0;
  TRISBbits.TRISB15 = 0;
*/
}

__attribute__((mips16)) void teardown_7seg_IOs() {
  LATB &= ~( (1<<0)|(1<<2)|(1<<3)|(1<<7)|(1<<8)|(1<<9)|(1<<10)|(1<<11)|(1<<12)|(1<<14)|(1<<15) );
  TRISB |= ( (1<<0)|(1<<2)|(1<<3)|(1<<7)|(1<<8)|(1<<9)|(1<<10)|(1<<11)|(1<<12)|(1<<14)|(1<<15) );
/*
  TRISBbits.TRISB0 = 0;
  TRISBbits.TRISB2 = 0;
  TRISBbits.TRISB3 = 0;
  TRISBbits.TRISB7 = 0;
  TRISBbits.TRISB8 = 0;
  TRISBbits.TRISB9 = 0;
  TRISBbits.TRISB10 = 0;
  TRISBbits.TRISB11 = 0;
  TRISBbits.TRISB12 = 0;
  TRISBbits.TRISB14 = 0;
  TRISBbits.TRISB15 = 0;
*/
}

__attribute__((mips16)) void setup_7seg_TMR() {
  T5CONbits.TCKPS = 1;
  IFS0bits.T5IF = 0;
  IPC5bits.T5IP = 4;
  IEC0bits.T5IE = 1;
  brightness = 256;
  PR5 = 7*brightness;
  T5CONbits.TON = 1;
  ClearWDT();
  EnableWDT();
}

__attribute__((mips16)) void teardown_7seg_TMR() {
  ClearWDT();
  DisableWDT();
  IEC0bits.T5IE = 0;
  IFS0bits.T5IF = 0;
  T5CON = 0;
}

__attribute__((mips16)) void display_test(delay_func pdelay_func) {
  int i;
  for( i = 0; i < 8; ++i ) {
      memset((void*)display, LAST_DIGIT + i + 1, 6);
      pdelay_func();
  }
  memset((void*)display, ' ', 6);
}
