'''
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

'''

__author__ = "Javier D. Garcia-Lasheras"
__copyright__ = "Copyright 2014, CERN"
__license__ = "GPLv3 or later"
__version__ = "1.0"
__maintainer__ = "Javier D. Garcia-Lasheras"
__email__ = "javier@garcialasheras.com"
__status__ = "Development"


from spec_demo_user import *


class SpecDemoUserDIO(SpecDemoUser):
    '''Simple demo application demonstrating the use of Spec class.
    This is part of the getting started with the SPEC project.
    By creating a SpecDemoUserDIO object, access to the basic functions
    covered in the gateware HDL Spec Demo User DIO is granted.
    In this way, the SPEC FPGA must be programmed with the specific bitstream.
    For this purpose, use the specLoadBitstream() method inherited from Spec.
    '''

    def __init__(self, bus=-1, dev=-1, libc='/usr/lib/libspec.so'):

        SpecDemoUser.__init__(self, bus=bus, dev=dev, libc=libc)

        self.dioBaseAddress = 0x100

        self.dioAddressMap = {
            'DDR':  0x00,
            'PSR':  0x04,
            'PDR':  0x08,
            'TERM': 0x0C,
            'SOPR': 0x10,
            'COPR': 0x14,
            'LED':  0x20,
        }

        self.dioLEDOffsets = {
            'Bottom': 0,
            'Top': 1,
        }


    # DIO Bottom LED Controls

    def dioGetBottomLED(self):
        '''Test the status of the DIO Front Panel Bottom LED.
        returns a nonzero result if the LED is ON, 0 if the LED is OFF.'''
        address = self.dioAddressMap['LED'] + self.dioBaseAddress
        offset = self.dioLEDOffsets['Bottom']
        return self.specTestBit(address, offset)

    def dioSetBottomLED(self):
        '''Set to ON the DIO Front Panel Bottom LED.'''
        address = self.dioAddressMap['LED'] + self.dioBaseAddress
        offset = self.dioLEDOffsets['Bottom']
        self.specSetBit(address, offset)

    def dioClearBottomLED(self):
        '''Clear to OFF the DIO Front Panel Bottom LED.'''
        address = self.dioAddressMap['LED'] + self.dioBaseAddress
        offset = self.dioLEDOffsets['Bottom']
        self.specClearBit(address, offset)

    def dioToggleBottomLED(self):
        '''Toggle/change the DIO Front Panel Bottom LED.'''
        address = self.dioAddressMap['LED'] + self.dioBaseAddress
        offset = self.dioLEDOffsets['Bottom']
        self.specToggleBit(address, offset)


    # DIO Top LED Controls

    def dioGetTopLED(self):
        '''Test the status of the DIO Front Panel Top LED.
        returns a nonzero result if the LED is ON, 0 if the LED is OFF.'''
        address = self.dioAddressMap['LED'] + self.dioBaseAddress
        offset = self.dioLEDOffsets['Top']
        return self.specTestBit(address, offset)

    def dioSetTopLED(self):
        '''Set to ON the DIO Front Panel Top LED.'''
        address = self.dioAddressMap['LED'] + self.dioBaseAddress
        offset = self.dioLEDOffsets['Top']
        self.specSetBit(address, offset)

    def dioClearTopLED(self):
        '''Clear to OFF the DIO Front Panel Top LED.'''
        address = self.dioAddressMap['LED'] + self.dioBaseAddress
        offset = self.dioLEDOffsets['Top']
        self.specClearBit(address, offset)

    def dioToggleTopLED(self):
        '''Toggle/change the DIO Front Panel Top LED.'''
        address = self.dioAddressMap['LED'] + self.dioBaseAddress
        offset = self.dioLEDOffsets['Top']
        self.specToggleBit(address, offset)


    # DIO pin controls 

    def dioWriteDirection(self, value):
        '''Set the DIO pin directions as a 5 chars string.
        Write char 1 for output and 0 for input.
        e.g. Pin 5 output, others input: value = '10000'.'''
        address = self.dioAddressMap['DDR'] + self.dioBaseAddress
        self.specWriteL(address, int(value, 2))

    def dioReadDirection(self):
        '''Return the DIO pin directions as a 5 chars string.
        Read char 1 for output and 0 for input.
        e.g. Pin 5 output, others input: return '10000'.'''
        address = self.dioAddressMap['DDR'] + self.dioBaseAddress
        register = self.specReadL(address, hexformat=False)
        return format(register, '05b')

    def dioReadValue(self):
        '''Return the DIO pin values as a 5 chars string.
        Read char 1 for HIGH and 0 for LOW.
        e.g. Pin 5 HIGH, others LOW: return '10000'.'''
        address = self.dioAddressMap['PSR'] + self.dioBaseAddress
        register = self.specReadL(address, hexformat=False)
        return format(register, '05b')

    def dioWriteValue(self, value):
        '''Set the DIO pin values as a 5 chars string.
        Write char 1 for HIGH and 0 for LOW.
        e.g. Pin 5 HIGH, others LOW: value = '10000'.'''
        address = self.dioAddressMap['PDR'] + self.dioBaseAddress
        self.specWriteL(address, int(value, 2))

    def dioWriteTermination(self, value):
        '''Set the DIO pin termination resistor as a 5 chars string.
        Write char 1 for termination ON and 0 for termination OFF.
        e.g. Pin 5 termination ON, others termination OFF: value = '10000'.'''
        address = self.dioAddressMap['TERM'] + self.dioBaseAddress
        self.specWriteL(address, int(value, 2))

    def dioReadTermination(self):
        '''Return the DIO pin termination resistor as a 5 chars string.
        Read char 1 for termination ON and 0 for termination OFF.
        e.g. Pin 5 termination ON, others termination OFF: return '10000'.'''
        address = self.dioAddressMap['TERM'] + self.dioBaseAddress
        register = self.specReadL(address, hexformat=False)
        return format(register, '05b')

    def dioSetOutput(self, value):
        '''Set to 1 the selected DIO pins as a 5 chars string.
        Write char 1 for selected and 0 for unchanged.
        e.g. Pin 5 set, others unchanged: value = '10000'.'''
        address = self.dioAddressMap['SOPR'] + self.dioBaseAddress
        self.specWriteL(address, int(value, 2))

    def dioClearOutput(self, value):
        '''Clear to 0 the selected DIO pins as a 5 chars string.
        Write char 1 for selected and 0 for unchanged.
        e.g. Pin 5 clear, others unchanged: value = '10000'.'''
        address = self.dioAddressMap['COPR'] + self.dioBaseAddress
        self.specWriteL(address, int(value, 2))


