# 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/decode.py
# class EdgeSequence(object):
#     '''Utility class to walk through an edge iterator in arbitrary time steps'''
# 
#     def __init__(self, edges, time_step, start_time=None):
#         '''
#         edges (sequence of (float, int) tuples)
#             An iterable of 2-tuples representing each edge transition.
#             The 2-tuples *must* be in the absolute time form (time, logic level).
#         
#         time_step (float)
#             The default time step for advance() when it is called
#             without an argument.
#         
#         start_time (float)
#             The initial starting time for the sequence.
#             
#         Raises StreamError when there are less than two elements to the edges iterable
#         '''
#         self.edges = edges
#         self.time_step = time_step
#         self.it_end = False
#         
#         try:
#             self.cur_states = next(self.edges)
#             self.next_states = next(self.edges)
#         except StopIteration:
#             self.it_end = True
#             raise StreamError('Not enough edges to initialize edge_sequence() object')
# 
#         self.cur_time = self.cur_states[0]
# 
#         if start_time is not None:
#             init_step = start_time - self.cur_time
#             if init_step > 0.0:
#                 self.advance(init_step)
# 
#         
#     def advance(self, time_step=None):
#         '''Move forward through edges by a given amount of time.
#         
#         time_step (float)
#             The amount of time to move forward. If None, the default
#             time_step from the constructor is used.
#         '''
#         if time_step == None:
#             time_step = self.time_step
#         
#         self.cur_time += time_step
#         while self.cur_time > self.next_states[0]:
#             self.cur_states = self.next_states
#             try:
#                 self.next_states = next(self.edges)
#             except StopIteration:
#                 self.it_end = True
#                 break
# 
# 
#     def advance_to_edge(self):
#         '''Advance to the next edge in the iterator after the current time
#         
#         Returns the amount of time advanced as a float.
#         '''
#         
#         if self.it_end:
#             return 0.0
#             
#         start_state = self.cur_states[1]
#         while self.cur_states[1] == start_state:
#             self.cur_states = self.next_states
#             
#             try:
#                 self.next_states = next(self.edges)
#             except StopIteration:
#                 # flag end of sequence if the state remains the same (no final edge)
#                 if self.cur_states[1] == start_state:
#                     self.it_end = True
#                 break
# 
#         time_step = self.cur_states[0] - self.cur_time
#         self.cur_time = self.cur_states[0]
#             
#         return time_step
#     
#     def cur_state(self):
#         '''The logic level of the edge iterator at the current time'''
#         return self.cur_states[1]
#     
#     def at_end(self):
#         '''Returns True when the edge iterator has terminated'''
#         return self.it_end


from ripyl.util.enum import Enum
from ripyl.decode import EdgeSequence
            yield (es.cur_time, 0)
            es.advance(low_time)

    yield (es.cur_time, es.cur_state()) # final state


def demodulate(edges, carrier_freq, polarity=IRConfig.IdleLow):
    '''Demodulate an edge stream

    This is a generator function.

    You can safely pass an unmodulated stream through this function without alteration

    edges (edge stream)
        The edge stream to modulate

    carrier_freq (float)
        The modulation frequency

    polarity (infrared.IRConfig)
        Set the polarity (idle state high or low)

    Yields an edge stream.
    '''
    # Invert edge polarity if idle-high
    if polarity == IRConfig.IdleHigh:
        edges = ((t, 1 - e) for t, e in edges)

    mod_period = (1.0 / carrier_freq)


# 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/decode.py
# class EdgeSequence(object):
#     '''Utility class to walk through an edge iterator in arbitrary time steps'''
# 
#     def __init__(self, edges, time_step, start_time=None):
#         '''
#         edges (sequence of (float, int) tuples)
#             An iterable of 2-tuples representing each edge transition.
#             The 2-tuples *must* be in the absolute time form (time, logic level).
#         
#         time_step (float)
#             The default time step for advance() when it is called
#             without an argument.
#         
#         start_time (float)
#             The initial starting time for the sequence.
#             
#         Raises StreamError when there are less than two elements to the edges iterable
#         '''
#         self.edges = edges
#         self.time_step = time_step
#         self.it_end = False
#         
#         try:
#             self.cur_states = next(self.edges)
#             self.next_states = next(self.edges)
#         except StopIteration:
#             self.it_end = True
#             raise StreamError('Not enough edges to initialize edge_sequence() object')
# 
#         self.cur_time = self.cur_states[0]
# 
#         if start_time is not None:
#             init_step = start_time - self.cur_time
#             if init_step > 0.0:
#                 self.advance(init_step)
# 
#         
#     def advance(self, time_step=None):
#         '''Move forward through edges by a given amount of time.
#         
#         time_step (float)
#             The amount of time to move forward. If None, the default
#             time_step from the constructor is used.
#         '''
#         if time_step == None:
#             time_step = self.time_step
#         
#         self.cur_time += time_step
#         while self.cur_time > self.next_states[0]:
#             self.cur_states = self.next_states
#             try:
#                 self.next_states = next(self.edges)
#             except StopIteration:
#                 self.it_end = True
#                 break
# 
# 
#     def advance_to_edge(self):
#         '''Advance to the next edge in the iterator after the current time
#         
#         Returns the amount of time advanced as a float.
#         '''
#         
#         if self.it_end:
#             return 0.0
#             
#         start_state = self.cur_states[1]
#         while self.cur_states[1] == start_state:
#             self.cur_states = self.next_states
#             
#             try:
#                 self.next_states = next(self.edges)
#             except StopIteration:
#                 # flag end of sequence if the state remains the same (no final edge)
#                 if self.cur_states[1] == start_state:
#                     self.it_end = True
#                 break
# 
#         time_step = self.cur_states[0] - self.cur_time
#         self.cur_time = self.cur_states[0]
#             
#         return time_step
#     
#     def cur_state(self):
#         '''The logic level of the edge iterator at the current time'''
#         return self.cur_states[1]
#     
#     def at_end(self):
#         '''Returns True when the edge iterator has terminated'''
#         return self.it_end


# Path: ripyl/protocol/infrared/ir_common.py
from ripyl.util.enum import Enum
from ripyl.decode import EdgeSequence

            yield (es.cur_time, 0)
            es.advance(low_time)

    yield (es.cur_time, es.cur_state()) # final state


def demodulate(edges, carrier_freq, polarity=IRConfig.IdleLow):
    '''Demodulate an edge stream

    This is a generator function.

    You can safely pass an unmodulated stream through this function without alteration

    edges (edge stream)
        The edge stream to modulate

    carrier_freq (float)
        The modulation frequency

    polarity (infrared.IRConfig)
        Set the polarity (idle state high or low)

    Yields an edge stream.
    '''
    # Invert edge polarity if idle-high
    if polarity == IRConfig.IdleHigh:
        edges = ((t, 1 - e) for t, e in edges)

    mod_period = (1.0 / carrier_freq)


    es = EdgeSequence(edges, mod_period)