
/// DIG_OUT.C
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "iodigital.h"
#include "ioserial.h"
#include "config.h"

/// check out periph.c for more details on the IO bit's setup
#ifndef USE_MCC_DIO

return_code_t dio_parse_bits( char *bit_str, unsigned long int *dest)
{
    return_code_t retval=ERR_FAILURE;
    if(NULL!=bit_str){
        char *cp=bit_str;
        unsigned long int bits=0;
         int i=0;
       while(*cp!='\0'){
           // find next token
           while(isspace(*cp))cp++;

           if(*cp=='V'){
               // valve *: all nA,nB,: one side of nth valve n:(both A&B)
                cp++;
                if(*cp=='*'){
                    // do all valves
                    *dest|=IO_SV_ALL;
                    retval=ERR_SUCCESS;
                }else if(isdigit(*cp)){
                    // is nA, nB or n (A&B)
                    if(sscanf(cp,"%d",&i)==1 && i<=SV8B){
                        // look for A/B
                        while(isdigit(*cp))cp++;
                        if(*cp=='A'){
                            *dest |= (1UL<<(SV0A+2*i));
                        }else if(*cp=='B'){
                            *dest |= (1UL<<(SV0B+2*i));
                        }else{
                            *dest |= (1UL<<(SV0A+2*i));
                            *dest |= (1UL<<(SV0B+2*i));
                        }
                       retval=ERR_SUCCESS;
                    }
                }

            }else if(*cp=='P'){
                // PUMP 0:1
                cp++;
                if(*cp=='A'){
                    // acid pump
                    *dest|=IO_PUMP_ACID;
                    retval=ERR_SUCCESS;
                }else if(*cp=='S'){
                    // acid pump
                    *dest|=IO_PUMP_SAMPLE;
                    retval=ERR_SUCCESS;
                }else if(*cp=='I' || *cp=='R'){
                    // air pump
                    *dest|=IO_PUMP_AIR;
                    retval=ERR_SUCCESS;
                }else if(*cp=='E' || *cp=='W'){
                    // seawater pump
                    *dest|=IO_PUMP_SEA;
                    retval=ERR_SUCCESS;
                }else if(*cp=='D'){
                    // DC pumps
                    *dest|=(IO_PUMP_SEA|IO_PUMP_AIR);
                    retval=ERR_SUCCESS;
                }else if(*cp=='X'){
                    // solenoid pumps
                    *dest|=(IO_PUMP_ACID|IO_PUMP_SAMPLE);
                    retval=ERR_SUCCESS;
                }else if(*cp=='*'){
                    // all pumps
                    *dest|=IO_PUMP_ALL;
                    retval=ERR_SUCCESS;
                }else if(isdigit(*cp)){
                    // is p0:3
                    if(sscanf(cp,"%d",&i)==1){
                        switch(i){
                            case 0:
                            case 1:
                                *dest |= (1UL << (PUMP0_DC+i));
                                break;
                            case 3:
                                *dest |= (1UL << (PUMP3_DC));
                                break;
                            case 2:
                                *dest |= (1UL << (PUMP2_DC));
                                break;
//                            case 4:
//                            case 5:
//                                *dest |= (1UL << (SV0A+i-4));
//                                break;
                            default:
                                // invalid
                                break;
                        }
                       retval=ERR_SUCCESS;
                    }
                }
            }else if(*cp=='A'){
                // ADC 0:1
                cp++;
                if(*cp=='*'){
                    // do all ADC enable bits
                    *dest|=IO_ADC_ALL;
                    retval=ERR_SUCCESS;
                }else if(isdigit(*cp)){

                    // is nA, nB or n (A&B)
                    if(sscanf(cp,"%d",&i)==1 && i<=1){
                        *dest |= (1UL << (ADC0+i));
                       retval=ERR_SUCCESS;
                    }
                }
            }else if(*cp=='L'){
                // licor DC power
                *dest |= (1UL << (LICOR_DC) );
                       retval=ERR_SUCCESS;
            }else if(*cp=='U'){
                // XCVR (C: console H: host L; licor)
                cp++;
                if(*cp=='C'){
                    *dest |= (1UL<<XCVR_CONS);
                    retval=ERR_SUCCESS;
                } else
                    if(*cp=='H'){
                    *dest |= (1UL<<XCVR_HOST);
                    retval=ERR_SUCCESS;
                }else if(*cp=='L'){
                    *dest |= (1UL<<XCVR_LICOR);
                    retval=ERR_SUCCESS;
                }
            }else if(*cp=='X' || *cp=='x'){
                // multiple bits (hex)
                cp++;
                if(isxdigit(*cp) && sscanf(cp,"%lx",&bits)==1){
                    *dest |= bits;
                    retval=ERR_SUCCESS;
                }
            }else if(*cp=='#'){
                // single bit (decimal)
                cp++;
                if(isdigit(*cp) && sscanf(cp,"%d",&i)==1 && i>=0 && i<IO_BITS){
                    *dest |= (1UL<<i);
                    retval=ERR_SUCCESS;
                }
            }else if(strstr(cp,"CX")==cp){
                uint32_t mask=0;
                if(config_get(cp,&mask)==ERR_SUCCESS){
                    *dest|=mask;
                    retval=ERR_SUCCESS;
                }
            }

           // find space at end of token
            while(!isspace(*cp) && *cp!='\0')cp++;
        }
    }
    return retval;

}

static return_code_t s_map_bit(io_bit_t bitnum, unsigned int *ioport, unsigned *iobit, bool sel)
{
    return_code_t retval=ERR_SUCCESS;

        switch (bitnum) {
            case SV0A:       *ioport=sel?P24_PORTE:P24_LATE; *iobit=P24_BIT0; break; //mPORTESetBits(IOPORT_BIT_0);return;
            case SV0B:       *ioport=sel?P24_PORTE:P24_LATE; *iobit=P24_BIT1; break; //mPORTESetBits(IOPORT_BIT_1);return;
            case SV1A:       *ioport=sel?P24_PORTE:P24_LATE; *iobit=P24_BIT2; break; //mPORTESetBits(IOPORT_BIT_2);return;
            case SV1B:       *ioport=sel?P24_PORTE:P24_LATE; *iobit=P24_BIT3; break; //mPORTESetBits(IOPORT_BIT_3);return;
            case SV2A:       *ioport=sel?P24_PORTE:P24_LATE; *iobit=P24_BIT4; break; //mPORTESetBits(IOPORT_BIT_4);return;
            case SV2B:       *ioport=sel?P24_PORTE:P24_LATE; *iobit=P24_BIT5; break; //mPORTESetBits(IOPORT_BIT_5);return;
            case SV3A:       *ioport=sel?P24_PORTF:P24_LATF; *iobit=P24_BIT0; break; //mPORTFSetBits(IOPORT_BIT_0);return;
            case SV3B:       *ioport=sel?P24_PORTF:P24_LATF; *iobit=P24_BIT1; break; //mPORTFSetBits(IOPORT_BIT_1);return;
            case SV4A:       *ioport=sel?P24_PORTD:P24_LATD; *iobit=P24_BIT4; break; //mPORTDSetBits(IOPORT_BIT_4);return;
            case SV4B:       *ioport=sel?P24_PORTD:P24_LATD; *iobit=P24_BIT5; break; //mPORTDSetBits(IOPORT_BIT_5);return;
            case SV5A:       *ioport=sel?P24_PORTD:P24_LATD; *iobit=P24_BIT6; break; //mPORTDSetBits(IOPORT_BIT_6);return;
            case SV5B:       *ioport=sel?P24_PORTD:P24_LATD; *iobit=P24_BIT7; break; //mPORTDSetBits(IOPORT_BIT_7);return;
            case SV6A:       *ioport=sel?P24_PORTC:P24_LATC; *iobit=P24_BIT13; break; //mPORTCSetBits(IOPORT_BIT_13);return;
            case SV6B:       *ioport=sel?P24_PORTD:P24_LATD; *iobit=P24_BIT0; break; //mPORTDSetBits(IOPORT_BIT_0);return;
            case SV7A:       *ioport=sel?P24_PORTD:P24_LATD; *iobit=P24_BIT11; break; //mPORTDSetBits(IOPORT_BIT_11);return;
            case SV7B:       *ioport=sel?P24_PORTD:P24_LATD; *iobit=P24_BIT10; break; //mPORTDSetBits(IOPORT_BIT_10);return;
            case SV8A:       *ioport=sel?P24_PORTD:P24_LATD; *iobit=P24_BIT9; break; //mPORTDSetBits(IOPORT_BIT_9);return;
            case SV8B:       *ioport=sel?P24_PORTG:P24_LATG; *iobit=P24_BIT2; break; //mPORTGSetBits(IOPORT_BIT_2);return;
            case SV9A:       *ioport=sel?P24_PORTG:P24_LATG; *iobit=P24_BIT3; break; //mPORTGSetBits(IOPORT_BIT_3);return;
            case SV9B:       *ioport=sel?P24_PORTC:P24_LATC; *iobit=P24_BIT14; break; //mPORTCSetBits(IOPORT_BIT_14);return;
            case PUMP0_DC:   *ioport=sel?P24_PORTB:P24_LATB; *iobit=P24_BIT3; break; //mPORTBSetBits(IOPORT_BIT_3);return;
            case PUMP1_DC:   *ioport=sel?P24_PORTB:P24_LATB; *iobit=P24_BIT2; break; //mPORTBSetBits(IOPORT_BIT_2);return;
            case PUMP2_DC:   *ioport=sel?P24_PORTG:P24_LATG; *iobit=P24_BIT9; break; //mPORTBSetBits(IOPORT_BIT_3);return;
            case PUMP3_DC:   *ioport=sel?P24_PORTB:P24_LATB; *iobit=P24_BIT1; break; //mPORTBSetBits(IOPORT_BIT_2);return;
            case LICOR_DC:   *ioport=sel?P24_PORTE:P24_LATE; *iobit=P24_BIT7; break; //mPORTESetBits(IOPORT_BIT_7);return;
            case ADC0:       *ioport=sel?P24_PORTB:P24_LATB; *iobit=P24_BIT12; break; //mPORTBSetBits(IOPORT_BIT_12);return;
            case ADC1:       *ioport=sel?P24_PORTB:P24_LATB; *iobit=P24_BIT13; break; //mPORTBSetBits(IOPORT_BIT_13);return;
//            case ADC2:       *ioport=sel?P24_PORTB:P24_LATB; *iobit=P24_BIT8; break; //mPORTBSetBits(IOPORT_BIT_13);return;
            case XCVR_HOST:  *ioport=sel?P24_PORTE:P24_LATE; *iobit=P24_BIT6; break; //mPORTESetBits(IOPORT_BIT_6);return;
            case XCVR_LICOR: *ioport=sel?P24_PORTG:P24_LATG; *iobit=P24_BIT8; break; //mPORTGSetBits(IOPORT_BIT_8);return;
            case XCVR_CONS:  *ioport=sel?P24_PORTD:P24_LATD; *iobit=P24_BIT3; break; //mPORTDSetBits(IOPORT_BIT_3);return;

//            case ADC2:
            default:
                retval=ERR_FAILURE;
        }

        return retval;
}

void doSetBit(io_bit_t bitnum, int state)
{
    unsigned int ioport=0xffff;
    unsigned int iobit=0xffff;

        if(s_map_bit(bitnum, &ioport, &iobit, true)==ERR_SUCCESS){
            if(state==0){
                P24_CLR_BITS(ioport,iobit);
            }else{
                P24_SET_BITS(ioport,iobit);
            }
        }

    Nop();
}
/// doSetBit

int doGetBit(io_bit_t bitnum)
{
    int retval=-1;
    unsigned int iolat=0xffff;
    unsigned int iobit=0xffff;

        if(s_map_bit(bitnum, &iolat, &iobit,false)==ERR_SUCCESS){
            retval = (P24_READ_LATCH_BIT(iolat,iobit)?1:0);
        }

    Nop();
    return retval;
}

void doSetBits(long unsigned int bits, int state) {
    long unsigned int i=0;

    // Can't set atomically/simultaneously?

    uint16_t portBbits=0x0000;
    uint16_t portCbits=0x0000;
    uint16_t portDbits=0x0000;
    uint16_t portEbits=0x0000;
    uint16_t portFbits=0x0000;
    uint16_t portGbits=0x0000;
    unsigned int ioport=0xffff;
    unsigned int iobit=0xffff;

    bits&=IO_ALL;
//    serPrintf(SER_CONS,"bits[%08lx] state[%d]\r\n",bits,state);
    for(i=0;i<IO_BITS;i++){
//        serPrintf(SER_CONS,"test[%08lx]\r\n",(1ul<<i));
        if(bits & (1ul<<i)){
            if(s_map_bit(i,&ioport,&iobit,true)==ERR_SUCCESS){
                switch(ioport){
                    case P24_PORTB:
                        portBbits |= iobit;
                        break;
                    case P24_PORTC:
                        portCbits |= iobit;
                        break;
                    case P24_PORTD:
                        portDbits |= iobit;
                        break;
                    case P24_PORTE:
                        portEbits |= iobit;
                        break;
                    case P24_PORTF:
                        portFbits |= iobit;
                        break;
                    case P24_PORTG:
                        portGbits |= iobit;
                        break;
                    default:
                        return;
                }
            }else{
                return;
            }
        }
    }

    if(state==0){
        P24_CLR_BITS(P24_LATB, portBbits);
        P24_CLR_BITS(P24_LATC, portCbits);
        P24_CLR_BITS(P24_LATD, portDbits);
        P24_CLR_BITS(P24_LATE, portEbits);
        P24_CLR_BITS(P24_LATF, portFbits);
        P24_CLR_BITS(P24_LATG, portGbits);
    }else{
        P24_SET_BITS(P24_LATB, portBbits);
        P24_SET_BITS(P24_LATC, portCbits);
        P24_SET_BITS(P24_LATD, portDbits);
        P24_SET_BITS(P24_LATE, portEbits);
        P24_SET_BITS(P24_LATF, portFbits);
        P24_SET_BITS(P24_LATG, portGbits);
    }

    Nop();
    return;
}

int doBlinkTog() {
    BLINK_TOGGLE();
    return (BLINK_GET() ? 1 : 0);
}

void doSetBlink(int state){
    BLINK_SET(state);
}

int doGetBlinky() {
    return BLINK_GET();
}

/// pin low means card is there
int doIsCardThere(){
    Nop();
    return SDC_DETECT();
}

#else
#warning "WITH_DIO disabled - using dio stubs"
void doSetBit(io_bit_t bitnum, int state)
{
    return;
}


int doGetBit(io_bit_t bitnum)
{
    return -1;
}


void doSetBlink(int state)
{
    return;
}


int doBlinkTog()
{
    return -1;
}


int doIsCardThere()
{
    return -1;
}


#endif /// USE_MCC_DIO
