# Path: ripyl/util/enum.py
# class Enum(object):
#     '''Base class for enumeration classes
#     
#     This provides a name() class method that will return the string
#     attribute name for an encoded enumeration value.
#     
#     e.g.
#     
#     >>> class Colors(Enum):
#     ...     blue = 1
#     ...     red = 2
#     ...     green = 3
#         
#     >>> Colors.name(Colors.red)
#     'red'
#     
#     >>> Colors.name(1, full_name=True)
#     'Colors.blue'
# 
#     "Instantiating" the Enum sub-class calls the name() method as well:
#     
#     >>> Colors(3, full_name=False)
#     'green'
#     
#     If necesssary you can use non-integers as the values as long as they are hashable:
#     
#     >>> class MathConst(Enum):
#     ...     pi = 3.2     # in certain US states :)
#     ...     e = 2.71828
#         
#     >>> MathConst.pi
#     3.2
#     
#     '''
# 
#     @classmethod
#     def name(cls, value, full_name=False):
#         '''Lookup the enumeration name with the provided value
# 
#         value (hashable)
#             A hashable Enum value (typically int) to find a name for.
# 
#         full_name (bool)
#             Include full name of Enum object in result
# 
#         Returns a string for the Enum attribute associated with value.
#         '''
#         
#         try:
#             enum_lookup = cls._enum_lookup
#         except AttributeError:
#             # Build inverse dict of class attributes with their values as key
#             enum_lookup = dict((v, k) for k, v in cls.__dict__.items() if k[0] != '_')
#             cls._enum_lookup = enum_lookup
#         
#         try:
#             aname = enum_lookup[value]
#             prefix = cls.__name__ + '.' if full_name else ''
#             return prefix + aname
# 
#         except KeyError:
#             return 'unknown'
# 
#     def __new__(cls, value, full_name=False):
#         '''Override class instantitation to perform name lookup instead'''
#         return cls.name(value, full_name)
# 
# Path: ripyl/sigproc.py
# def remove_excess_edges(edges):
#     '''Remove incorrect edge transitions from an edge stream
#     
#     This is a generator function.
#     
#     This function is most useful for conditioning the outputs of the protocol
#     synthesizers. For those protocols with multiple signals, the synthesizers
#     myst yield a new output set for *all* signals when any *one* of them changes.
#     This results in non-conforming edge streams that contain multiple consecutive
#     pairs with a non-changing value.
#     
#     edges (iterable of (float, int) tuples)
#         An edge stream to filter for extraneous non-edges
#         
#     Yields an edge stream.
#     '''
#     prev_state = None
#     last_e = None
#     for e in edges:
#         if prev_state is None:
#             prev_state = e[1]
#             yield e
#         else:
#             if e[1] != prev_state:
#                 prev_state = e[1]
#                 last_e = None
#                 yield e
#             else: # Save last edge so we can yield it at the end
#                 last_e = e
#         
#     if last_e is not None:
#         yield last_e


import itertools
import ripyl.streaming as stream
from ripyl.decode import *
from ripyl.util.enum import Enum
from ripyl.util.bitops import *
from ripyl.sigproc import remove_excess_edges
def i2c_synth(transfers, clock_freq, idle_start=0.0, transfer_interval=0.0, idle_end=0.0):
    '''Generate synthesized I2C waveforms
    
    This function simulates I2C transfers on the SCL and SDA signals.

    transfers (sequence of I2CTransfer objects)
        Data to be synthesized.
    
    clock_freq (float)
        Clock frequency for the I2C bus. Standard rates are 100kHz (100.0e3)
        and 400kHz (400.0e3) but any frequency can be specified.
    
    idle_start (float)
        The amount of idle time before the transmission of transfers begins

    transfer_interval (float)
        The amount of time between transfers
    
    idle_end (float)
        The amount of idle time after the last transfer
    
    Returns a pair of iterators representing the two edge streams for scl, and sda
      respectively. Each edge stream pair is in (time, value) format representing the
      time and logic value (0 or 1) for each edge transition. The first elements in the
      iterators are the initial state of the waveforms.
    '''
    # This is a wrapper around the actual synthesis code in _i2c_synth()
    # It unzips the yielded tuple and removes unwanted artifact edges
    scl, sda = itertools.izip(*_i2c_synth(transfers, clock_freq, idle_start, transfer_interval, idle_end))
    scl = remove_excess_edges(scl)

# Path: ripyl/util/enum.py
# class Enum(object):
#     '''Base class for enumeration classes
#     
#     This provides a name() class method that will return the string
#     attribute name for an encoded enumeration value.
#     
#     e.g.
#     
#     >>> class Colors(Enum):
#     ...     blue = 1
#     ...     red = 2
#     ...     green = 3
#         
#     >>> Colors.name(Colors.red)
#     'red'
#     
#     >>> Colors.name(1, full_name=True)
#     'Colors.blue'
# 
#     "Instantiating" the Enum sub-class calls the name() method as well:
#     
#     >>> Colors(3, full_name=False)
#     'green'
#     
#     If necesssary you can use non-integers as the values as long as they are hashable:
#     
#     >>> class MathConst(Enum):
#     ...     pi = 3.2     # in certain US states :)
#     ...     e = 2.71828
#         
#     >>> MathConst.pi
#     3.2
#     
#     '''
# 
#     @classmethod
#     def name(cls, value, full_name=False):
#         '''Lookup the enumeration name with the provided value
# 
#         value (hashable)
#             A hashable Enum value (typically int) to find a name for.
# 
#         full_name (bool)
#             Include full name of Enum object in result
# 
#         Returns a string for the Enum attribute associated with value.
#         '''
#         
#         try:
#             enum_lookup = cls._enum_lookup
#         except AttributeError:
#             # Build inverse dict of class attributes with their values as key
#             enum_lookup = dict((v, k) for k, v in cls.__dict__.items() if k[0] != '_')
#             cls._enum_lookup = enum_lookup
#         
#         try:
#             aname = enum_lookup[value]
#             prefix = cls.__name__ + '.' if full_name else ''
#             return prefix + aname
# 
#         except KeyError:
#             return 'unknown'
# 
#     def __new__(cls, value, full_name=False):
#         '''Override class instantitation to perform name lookup instead'''
#         return cls.name(value, full_name)
# 
# Path: ripyl/sigproc.py
# def remove_excess_edges(edges):
#     '''Remove incorrect edge transitions from an edge stream
#     
#     This is a generator function.
#     
#     This function is most useful for conditioning the outputs of the protocol
#     synthesizers. For those protocols with multiple signals, the synthesizers
#     myst yield a new output set for *all* signals when any *one* of them changes.
#     This results in non-conforming edge streams that contain multiple consecutive
#     pairs with a non-changing value.
#     
#     edges (iterable of (float, int) tuples)
#         An edge stream to filter for extraneous non-edges
#         
#     Yields an edge stream.
#     '''
#     prev_state = None
#     last_e = None
#     for e in edges:
#         if prev_state is None:
#             prev_state = e[1]
#             yield e
#         else:
#             if e[1] != prev_state:
#                 prev_state = e[1]
#                 last_e = None
#                 yield e
#             else: # Save last edge so we can yield it at the end
#                 last_e = e
#         
#     if last_e is not None:
#         yield last_e


# Path: ripyl/protocol/i2c.py
import itertools
import ripyl.streaming as stream
from ripyl.decode import *
from ripyl.util.enum import Enum
from ripyl.util.bitops import *
from ripyl.sigproc import remove_excess_edges

def i2c_synth(transfers, clock_freq, idle_start=0.0, transfer_interval=0.0, idle_end=0.0):
    '''Generate synthesized I2C waveforms
    
    This function simulates I2C transfers on the SCL and SDA signals.

    transfers (sequence of I2CTransfer objects)
        Data to be synthesized.
    
    clock_freq (float)
        Clock frequency for the I2C bus. Standard rates are 100kHz (100.0e3)
        and 400kHz (400.0e3) but any frequency can be specified.
    
    idle_start (float)
        The amount of idle time before the transmission of transfers begins

    transfer_interval (float)
        The amount of time between transfers
    
    idle_end (float)
        The amount of idle time after the last transfer
    
    Returns a pair of iterators representing the two edge streams for scl, and sda
      respectively. Each edge stream pair is in (time, value) format representing the
      time and logic value (0 or 1) for each edge transition. The first elements in the
      iterators are the initial state of the waveforms.
    '''
    # This is a wrapper around the actual synthesis code in _i2c_synth()
    # It unzips the yielded tuple and removes unwanted artifact edges
    scl, sda = itertools.izip(*_i2c_synth(transfers, clock_freq, idle_start, transfer_interval, idle_end))
    scl = remove_excess_edges(scl)

    sda = remove_excess_edges(sda)