def __init__(self, 
              spi_device = None, 
              vref = DEFAULT_VREF,
             ):
     self._spi = CommSPI(device = spi_device)
     self.vref       = float(vref)
     self.resolution = 2**self.BIT_RESOLUTION - 1
     self.scale      = self.vref/self.resolution
class MCP3008ADC(object):
    """ Interface for MCP3008 8-Channel 10-Bit A/D Converters
        with SPI Serial Interface.  
    
        Hardware mode SPI can be used by specifying 'device' 
        during initialization or through 'setup_hardware_spi'.
        
        Software mode SPI (bit-banged) can configured using 
        'setup_software_spi'.  
    """
    NUM_CHANNELS   = 8
    MODEL          = 'MCP3008'
    BIT_RESOLUTION = 10
    def __init__(self, 
                 spi_device = None, 
                 vref = DEFAULT_VREF,
                ):
        self._spi = CommSPI(device = spi_device)
        self.vref       = float(vref)
        self.resolution = 2**self.BIT_RESOLUTION - 1
        self.scale      = self.vref/self.resolution
        
    def setup_hardware_spi(self, device):
        """ configure the driver for hardware communications at the port 
            specified by 'device', i.e. "/dev/spidev0.0"
        """ 
        self._spi.setup_hardware(device)
    
    def setup_software_spi(self, clockpin, mosipin, misopin, cspin, pinmode):
        """ setup the GPIO pins to perform software (bit-banged) communications
        """ 
        self._spi.setup_software(clockpin, mosipin, misopin, cspin, pinmode)
        
    def read(self, chan, mode = 's'):
        """ get the ADC voltage scaled value in specified 'mode':
              's': single-ended, chan = IN+, gnd = IN-
              'd': differential, for each channel pair
                   e.g. chan = 0 => CH0 = IN+, CH1 = IN-
                        chan = 1 => CH0 = IN-, CH1 = IN+
        """
        raw_val = self.read_raw(chan=chan,mode=mode)
        V = raw_val*self.scale
        return V
        
    def read_raw(self, chan, mode = 's'):
        """ get the raw ADC value in specified 'mode':
              's': single-ended, chan = IN+, gnd = IN-
              'd': differential, for each channel pair
                   e.g. chan = 0 => CH0 = IN+, CH1 = IN-
                        chan = 1 => CH0 = IN-, CH1 = IN+
        """
        if not chan in range(self.NUM_CHANNELS):
            raise ValueError, "'chan' must be in %r" % range(self.NUM_CHANNELS)
        #command byte is (sgl/diff,D2,D1,D0,X,X,X,X)
        cmd  = None
        if   mode == 's':
            cmd  = 1 << 7        #single-ended bit
        elif mode == 'd':
            cmd  = 0             #differential, null bit
        else:
            raise ValueError, "mode must be 's' (or 'diff'"
        cmd |= chan << 4         #D2,D1,D0
        raw_val = self._run_transaction(cmd)
        return raw_val
        
    def _run_transaction(self, cmd):
        bytes_out = bytearray()
        bytes_out.append(0x01)   #start bit
        #command byte is (sgl/diff,D2,D1,D0,X,X,X,X)
        bytes_out.append(cmd)
        #extra byte to receive data
        bytes_out.append(0)
        #do transmit/receive
        bytes_in = self._spi.transfer(bytes_out)
        #data is in 2nd and 3rd bytes (?,?,?,?,?,0,B9,B8), (B7,B6,B5,B4,B3,B2,B1,B0)
        #print " ".join(map(bin,bytes_in))
        val  = (bytes_in[1] & 0b11) << 8
        val += bytes_in[2]
        return val