//dice/coin/random card emulator with OLED
//Noise Multiplier Hardware (modular entropy multiplier) + software LFSR
//See .h files for most pins

#include "config.h"
#include <xc.h>
//all here:
#include "util.h"

//see Properties for _XTAL_FREQ (compiler/preprocessing/define macros) _XTAL_FREQ=(16000000UL)
        
void main(void) {
    lfsr_data32=lfsrEEPROM; //load from EEPROM at boot
    ioInit();
    startUp();
    GIE=1;
    loadRoll();
    drawBorderCurrent();    
    while(1){
        lowPowerWait();
        if(settingsMode){
            if(checkButton(BACK_BUTTON)){
                settingsMode=0;                                    
                udFlag=1;
                OLEDclear(0);
                drawBorderCurrent(); 
                timerReset();
                rollFromSleep=0;    //might get set
            }
            OLEDpage=4;                            
            OLEDcol=0;
            switch(settingsMode){
                case SETTINGS_START:
                    settingsMode=1;
                    settingsTitle();
                    break;
                case SETTINGS_TIMEOUT:
                    if(checkButton(UP_BUTTON)){if(timeOut<TIMEOUT_MAX){timeOut=timeOut+TIMEOUT_STEP;}}
                    if(checkButton(DOWN_BUTTON)){if(timeOut>TIMEOUT_MIN){timeOut=timeOut-TIMEOUT_STEP;}}
                    OLEDchararray("UP/DN TO EDIT",arial);
                    OLEDpage=6;                            
                    OLEDcol=80;
                    OLEDscanshort(timeOut);
                    OLEDlzb(8);
                    OLEDchararray(&OLEDbuf[7],arial);
                    OLEDchar('s',arial);
                    break;
                case SETTINGS_BRIGHTNESS:
                    if(checkButton(UP_BUTTON)){
                        if(oledBrightness<BRIGHTNESS_MAX){
                            oledBrightness=oledBrightness+BRIGHTNESS_STEP;
                            OLEDbrightness(oledBrightness);
                        }
                    }
                    if(checkButton(DOWN_BUTTON)){
                        if(oledBrightness>BRIGHTNESS_MIN){
                            oledBrightness=oledBrightness-BRIGHTNESS_STEP;
                            OLEDbrightness(oledBrightness);
                        }
                    }
                    OLEDchararray("UP/DN TO EDIT",arial);
                    OLEDpage=6;                            
                    OLEDcol=80;
                    OLEDscanshort(oledBrightness/2);        //roughly map to %
                    OLEDlzb(8);
                    OLEDchararray(&OLEDbuf[7],arial);
                    OLEDchar('%',arial);
                    break;
#ifdef ALLOW_OLED_X_SETTING
                case SETTINGS_OLEDX:
                    if(checkButton(UP_BUTTON)){
                        if(oledXoffset<OLED_X_OFFSET_MAX){
                            oledXoffset=oledXoffset+1;
                            settingsTitle();    //redraw
                        }
                    }
                    if(checkButton(DOWN_BUTTON)){
                        if(oledXoffset>OLED_X_OFFSET_MIN){
                            oledXoffset=oledXoffset-1;
                            settingsTitle();    //redraw
                        }
                    }
                    OLEDpage=4;                            
                    OLEDcol=0;
                    OLEDchararray("UP/DN TO EDIT",arial);
                    OLEDpage=6;                            
                    OLEDcol=0;
                    OLEDchar(0,xAlign);
                    OLEDpage=6;                            
                    OLEDcol=42;
                    OLEDchararray("X=",arial);
                    if(oledXoffset<0){
                        OLEDchar('-',arial);
                    }else{
                        OLEDchar('+',arial);                        
                    }
                    OLEDscanshort((unsigned int)(abs(oledXoffset)));
                    OLEDchar(OLEDbuf[9],arial);
                    OLEDpage=6;                            
                    OLEDcol=119;
                    OLEDchar(1,xAlign);
                    break;
#endif //ALLOW_OLED_X_SETTING
                case SETTINGS_SHAKE_WAKE:
                    if(shakeToWake){
                        OLEDchararray("WAKE IS ON.   ",arial);
                        OLEDpage=6;                            
                        OLEDcol=0;
                        OLEDchararray("DOWN FOR OFF  ",arial);
                        if(checkButton(DOWN_BUTTON)){shakeToWake=0;}
                    }else{
                        OLEDchararray("WAKE IS OFF.  ",arial);
                        OLEDpage=6;                            
                        OLEDcol=0;
                        OLEDchararray("UP FOR ON     ",arial);
                        if(checkButton(UP_BUTTON)){shakeToWake=1;}
                    }                    
                    break;
                case SETTINGS_MEMTEST:
                    OLEDchararray("PRESS UP",arial);
                    OLEDpage=6;                            
                    OLEDcol=0;
                    OLEDchararray("TO RUN TEST.",arial);
                    if(checkButton(UP_BUTTON)){         //test runs synchronously
                        OLEDclear(0);
                        runMEMtest();
                        OLEDclear(0);
                        settingsTitle();
                    }
                    break;
                case SETTINGS_USEMEM:
                    if(useMEM){
                        OLEDchararray("MULT. IS ON   ",arial);
                        OLEDpage=6;                            
                        OLEDcol=0;
                        OLEDchararray("DOWN FOR OFF  ",arial);
                        if(checkButton(DOWN_BUTTON)){useMEM=0;}
                    }else{
                        OLEDchararray("MULT. IS OFF  ",arial);
                        OLEDpage=6;                            
                        OLEDcol=0;
                        OLEDchararray("UP FOR ON     ",arial);
                        if(checkButton(UP_BUTTON)){useMEM=1;}
                    }
                    break;
                default:    //handle rolls
                    if((settingsMode>=SETTINGS_DUMMY)&&(settingsMode<SETTINGS_LAST)){                        
                        s=rollName(eePairs[settingsMode-SETTINGS_DUMMY].lhs);
                        OLEDchararray("LEFT:",smallFont);
                        OLEDchararray(s,smallFont);
                        if(eePairs[settingsMode-SETTINGS_DUMMY].lhs.colour==WHITE){
                            OLEDchararray(", WHITE",smallFont);
                        }else{
                            OLEDchararray(", BLACK",smallFont);                            
                        }
                        OLEDpage=5;                            
                        OLEDcol=0;
                        s=rollName(eePairs[settingsMode-SETTINGS_DUMMY].rhs);
                        OLEDchararray("RIGHT:",smallFont);
                        OLEDchararray(s,smallFont);
                        if(eePairs[settingsMode-SETTINGS_DUMMY].rhs.colour==WHITE){
                            OLEDchararray(", WHITE",smallFont);
                        }else{
                            OLEDchararray(", BLACK",smallFont);                            
                        }                        
                        OLEDpage=6;                            
                        OLEDcol=0;
                        OLEDchararray("UP TO CHANGE",arial);
                        if(checkButton(UP_BUTTON)){         //runs synchronously
                            OLEDclear(0);
                            setRoll((unsigned char)(settingsMode-SETTINGS_DUMMY));
                            OLEDclear(0);
                            settingsTitle();
                        }                        
                    }
                    break;
            }
            if(checkButton(LEFT_BUTTON)){
                settingsMode=settingsMode-1;
                if(settingsMode==0){settingsMode=(SETTINGS_LAST-1);}
                settingsTitle();
            }
            if(checkButton(RIGHT_BUTTON)){
                settingsMode=settingsMode+1;
                if(settingsMode>=SETTINGS_LAST){settingsMode=1;}
                settingsTitle();
            }
        }else{
            if(udFlag){
                udFlag=0;
                vcc=getVCC();
                OLEDpage=0;        
                OLEDcol=0;
                if((vcc<VCC_MIN)&&(tmOut&1)){   //flash if low
                    OLEDscanshort(vcc);
                    OLEDchar(' ',smallFont);
                    OLEDchar(' ',smallFont);
                    OLEDchar(' ',smallFont);
                    OLEDchar(' ',smallFont);
                }else{
                    OLEDscanshort(vcc);
                    OLEDchar(OLEDbuf[6],smallFont);  //volts
                    OLEDchar('.',smallFont);
                    OLEDchar(OLEDbuf[7],smallFont);  //tenths of a volt
                    OLEDchar('V',smallFont);
                }
                OLEDscanshort(tmOut/4);                    
                OLEDpage=0;        
                OLEDcol=108;
                OLEDlzb(8);
                OLEDchararray(&OLEDbuf[7],smallFont);        
            }
            if(checkButton(LEFT_BUTTON)){
                newIndex=1;
                if(currentIndex==0){
                    currentIndex=TEMPLATE_COUNT+EE_PAIRS-1;
                }else{
                    currentIndex=currentIndex-1;
                }
                lhsResult=0;    //reset on view change
                rhsResult=0;
            }
            if(checkButton(RIGHT_BUTTON)){
                newIndex=1;
                currentIndex=currentIndex+1;
                if(currentIndex>(TEMPLATE_COUNT+EE_PAIRS-1)){
                    currentIndex=0;
                }
                lhsResult=0;    //reset on view change
                rhsResult=0;
            }
            if(checkButton(DOWN_BUTTON)){
                newIndex=1;   //force redraw
                lhsResult=0;    //reset on view change
                rhsResult=0;
            }
            if(newIndex){
                newIndex=0;
                loadRoll();
                OLEDclear(0);
                drawBorderCurrent();
                timerReset();
            }
            if(buttonState(UP_BUTTON) || rollFromSleep || buttonState(SHAKE_BUTTON)){
                rollFromSleep=0;
                while(buttonState(UP_BUTTON)){ //SHAKE_BUTTON isn't likely to stay low for long, so ignore for now
                    getSelectedBit();
                    drawGraphics(&current.lhs,getRollLFSR(current.lhs.roll)); //simulate rolling motion
                    drawGraphics(&current.rhs,getRollLFSR(current.rhs.roll));                
                }
                do{ //perform repeated rolls while down held
                    n=getSelectedRoll(ROLL_RUNON)+ROLL_RUNON;
                    while(n--){
                        __delay_ms(ROLL_RUNDOWN);
                        drawGraphics(&current.lhs,getRollLFSR(current.lhs.roll)); //simulate rolling motion
                        drawGraphics(&current.rhs,getRollLFSR(current.rhs.roll));                
                    }
                    lhsResult=getSelectedRoll(current.lhs.roll);
                    rhsResult=getSelectedRoll(current.rhs.roll);
                    drawGraphics(&current.lhs,lhsResult); //final roll
                    drawGraphics(&current.rhs,rhsResult);                
                    OLEDscanshort(lhsResult);                    
                    OLEDlzb(8);
                    uartSends(&OLEDbuf[7]);    
                    if(current.rhs.disp!=DISP_NULL){
                        uartSend(',');
                        OLEDscanshort(rhsResult);                    
                        OLEDlzb(8);
                        uartSends(&OLEDbuf[7]);                            
                    }
                    uartSend('\r');
                    uartSend('\n');
                    timerReset();
                }while(buttonState(DOWN_BUTTON));
            }
            if(buttonState(BACK_BUTTON)||buttonState(OK_BUTTON)){
                timerReset();
            }
            if(buttonState(BACK_BUTTON)&&buttonState(OK_BUTTON)){           //hold both to enter
                OLEDclear(0);
                while(buttonState(BACK_BUTTON)||buttonState(OK_BUTTON)){    
                    __delay_ms(10); //debouncing
                    settingsMode=SETTINGS_START;                    
                }
            }
            if(tmOut==0){   //sleep 
                shutDown();
                sleepAndWakeup();
                startUp();
                udFlag=1;
                OLEDclear(0);
                drawBorderCurrent();                 
                if(lhsResult){
                    drawGraphics(&current.lhs,lhsResult); //show last roll                    
                }
                if(rhsResult){
                    drawGraphics(&current.rhs,rhsResult); //show last roll                    
                }
            }
            if(tmOut<(OLED_DIM_TIME*T0_FREQ)){
                if(OLEDisDim==0){
                    OLEDisDim=1;
                    OLEDbrightness((OLED_DIM_LEVEL+oledBrightness)/2);
                }
            }else{
                if(OLEDisDim){
                    OLEDisDim=0;
                    OLEDbrightness(oledBrightness);
                }                
            }
        }
    }
}

void __interrupt() isr(){
    if(PIR0bits.TMR0IF && PIE0bits.TMR0IE){
        PIR0bits.TMR0IF=0;        
        if(tmOut){tmOut--;}
        if(udFlag<1){udFlag=1;}        
    }
    if(PIE0bits.IOCIE){ //only if actually sleeping
        if(iocxfbits.S3 && buttonState(UP_BUTTON)){rollFromSleep=1;}
        if(iocxfbits.S7 && buttonState(SHAKE_BUTTON)){rollFromSleep=1;}        
    }
    if(IOCAF || IOCBF || IOCCF){
        CPUDOZE=0;
        IOCAF=0;
        IOCBF=0;
        IOCCF=0;
    }
    uartISR();
}
