def rc5_synth(messages, idle_start=0.0, message_interval=89.0e-3, idle_end=1.0e-3): '''Generate synthesized RC5 infrared waveforms This function simulates Philips RC5 IR pulses. messages (sequence of RC5Message) Commands to be synthesized. idle_start (float) The amount of idle time before the transmission of messages begins. message_interval (float) The amount of time between messages. idle_end (float) The amount of idle time after the last message. Yields an edge stream of (float, int) pairs. The first element in the iterator is the initial state of the stream. ''' t = 0.0 pulse_width = 889.0e-6 # 889us pulse width yield (t, 0) # set initial conditions; idle-low t += idle_start for msg in messages: msg_bits = [1, 0 if (msg.cmd & 0x40) else 1, msg.toggle] msg_bits.extend(split_bits(msg.addr, 5)) msg_bits.extend(split_bits(msg.cmd, 6)) #print('### msg_bits:', msg_bits) coded_bits = ((0, 1) if b else (1, 0) for b in msg_bits ) # Expand each bit into a pair of half bits coded_bits = (b for sl in coded_bits for b in sl) # Flatten the tuples prev_state = 0 for b in coded_bits: if b != prev_state: yield (t, b) t += pulse_width prev_state = b if prev_state == 1: yield (t, 0) t += message_interval t += idle_end - message_interval yield (t, 0) # Final state
def rc5_synth(messages, idle_start=0.0, message_interval=89.0e-3, idle_end=1.0e-3): '''Generate synthesized RC5 infrared waveforms This function simulates Philips RC5 IR pulses. messages (sequence of RC5Message) Commands to be synthesized. idle_start (float) The amount of idle time before the transmission of messages begins. message_interval (float) The amount of time between messages. idle_end (float) The amount of idle time after the last message. Yields an edge stream of (float, int) pairs. The first element in the iterator is the initial state of the stream. ''' t = 0.0 pulse_width = 889.0e-6 # 889us pulse width yield (t, 0) # set initial conditions; idle-low t += idle_start for msg in messages: msg_bits = [1, 0 if (msg.cmd & 0x40) else 1, msg.toggle] msg_bits.extend(split_bits(msg.addr, 5)) msg_bits.extend(split_bits(msg.cmd, 6)) #print('### msg_bits:', msg_bits) coded_bits = ((0, 1) if b else (1, 0) for b in msg_bits) # Expand each bit into a pair of half bits coded_bits = (b for sl in coded_bits for b in sl) # Flatten the tuples prev_state = 0 for b in coded_bits: if b != prev_state: yield (t, b) t += pulse_width prev_state = b if prev_state == 1: yield (t, 0) t += message_interval t += idle_end - message_interval yield (t, 0) # Final state
def lin_pid(id): '''Generate a LIN PID from an ID id (int) The ID to generate parity for Returns the PID as an int. ''' p0 = reduce(operator.xor, split_bits(id & _p0_mask, 6)) p1 = reduce(operator.xor, split_bits(id & _p1_mask, 6)) ^ 0x01 return join_bits([p1, p0] + split_bits(id, 6))
def bit_stream(self): '''Get the sequence of raw bits for the frame. This includes the SOF and SFD at the start and the IDL phase at end of frame. ''' for b in [0x55] * 7 + [0xD5]: # SOF + SFD for bit in reversed(split_bits(b, 8)): yield bit for b in self.bytes: for bit in reversed(split_bits(b, 8)): yield bit # IDL = high for 3 bit times -> 6 half-bit times for bit in [ManchesterStates.High] * 6: yield bit yield ManchesterStates.Idle
def vpw_encode(bytes, start_time): '''Convert bytes to a VPW edge sequence bytes (sequence of int) The bytes to encode start_time (float) The Start time for the first edge Returns a list of (float, int) edge pairs. ''' is_passive = 1 edges = [] t = start_time for byte in bytes: for b in split_bits(byte, 8): if is_passive: edges.append((t, 0)) pw = 64.0e-6 if b == 0 else 128.0e-6 else: # Active edges.append((t, 1)) pw = 64.0e-6 if b == 1 else 128.0e-6 t += pw is_passive = 1 - is_passive # Each frame has an even number of bits which guarantees the last bit # was in the active state. Thus there should be a falling edge at the # current time to end the last bit. edges.append((t, 0)) return edges
def pwm_encode(bytes, start_time, bit_slice): '''Convert bytes to a PWM edge sequence bytes (sequence of int) The bytes to encode start_time (float) The Start time for the first edge bit_slice (float) The time for 1/3 of a bit period. Returns a list of (float, int) edge pairs. ''' edges = [] t = start_time for byte in bytes: for b in split_bits(byte, 8): edges.append((t, 1)) pw = bit_slice if b == 1 else bit_slice * 2 t += pw edges.append((t, 0)) t += 3 * bit_slice - pw edges.append((t, 0)) return edges
def pwm_encode(bytes, start_time, bit_slice): '''Convert bytes to a PWM edge sequence bytes (sequence of int) The bytes to encode start_time (float) The Start time for the first edge bit_slice (float) The time for 1/3 of a bit period. Returns a list of (float, int) edge pairs. ''' edges = [] t = start_time for byte in bytes: for b in split_bits(byte, 8): edges.append((t, 1)) pw = bit_slice if b == 1 else bit_slice * 2 t += pw edges.append((t, 0)) t += 3*bit_slice - pw edges.append((t, 0)) return edges
def edges(self, bit_period): '''Get the edges for this object bit_period (float) The period of a single bit. Returns a list of (float, int) edges representing the pulse(s) for this object ''' if self.link_code is None: return [(0.0, 1), (bit_period, ManchesterStates.Idle), (2 * bit_period, ManchesterStates.Idle)] else: #print('## code word:', '{:016b}'.format(self.link_code.word)) code_bits = reversed(split_bits(self.link_code.word, 16)) edges = [] t = 0.0 for b in code_bits: edges.extend([(t, 1), (t + bit_period, ManchesterStates.Idle)]) if b == 1: t += 62.5e-6 edges.extend([(t, 1), (t + bit_period, ManchesterStates.Idle)]) t += 62.5e-6 else: # 0 t += 125.0e-6 # Last framing pulse edges.extend([(t, 1), (t + bit_period, ManchesterStates.Idle), (t + 2 * bit_period, ManchesterStates.Idle)]) return edges
def edges(self, bit_period): '''Get the edges for this object bit_period (float) The period of a single bit. Returns a list of (float, int) edges representing the pulse(s) for this object ''' if self.link_code is None: return [(0.0, 1), (bit_period, ManchesterStates.Idle), (2*bit_period, ManchesterStates.Idle)] else: #print('## code word:', '{:016b}'.format(self.link_code.word)) code_bits = reversed(split_bits(self.link_code.word, 16)) edges = [] t = 0.0 for b in code_bits: edges.extend([(t, 1), (t + bit_period, ManchesterStates.Idle)]) if b == 1: t += 62.5e-6 edges.extend([(t, 1), (t + bit_period, ManchesterStates.Idle)]) t += 62.5e-6 else: # 0 t += 125.0e-6 # Last framing pulse edges.extend([(t, 1), (t + bit_period, ManchesterStates.Idle), (t + 2*bit_period, ManchesterStates.Idle)]) return edges
def _get_drive_cycle_status(a, b, c, d): '''Decode response for sid 0x01, pid 0x41''' test_available = [bool(v) for v in split_bits(b & 0x0F, 4)] test_incomplete = [bool(v) for v in split_bits((b & 0xF0) >> 4, 4)] b_tests = ['misfire', 'fuel system', 'components', 'reserved_in_b'] tests = {} for tname, ta, tc in zip(b_tests, test_available, test_incomplete): tests[tname] = (ta, tc) test_available = [bool(v) for v in split_bits(c, 8)] test_incomplete = [bool(v) for v in split_bits(d, 8)] spark_tests = ['catalyst', 'heated catalyst', 'evap. system', \ 'secondary air system', 'A/C refrigerant', 'oxygen sensor', \ 'oxygen sensor heater', 'EGR system'] for tname, ta, tc in zip(spark_tests, test_available, test_incomplete): tests[tname] = (ta, tc) return tests
def _get_supported_pids(offset, a, b, c, d): '''Decode the response to SID 0x01 PID 0x00, 0x20, 0x40, 0x60 requests offset (int) The offset for the PID (0x00, 0x20, etc.) a,b,c,d (sequence of ints) The four bytes of the response Returns a sequence of integers for each suported PID. ''' merged_code = ((a * 256 + b) * 256 + c) * 256 + d pid_bits = split_bits(merged_code, 32) pids = [] for i, b in enumerate(pid_bits): if b == 1: pids.append(i + 1 + offset) return pids
def _get_supported_pids(offset, a, b, c, d): '''Decode the response to SID 0x01 PID 0x00, 0x20, 0x40, 0x60 requests offset (int) The offset for the PID (0x00, 0x20, etc.) a,b,c,d (sequence of ints) The four bytes of the response Returns a sequence of integers for each suported PID. ''' merged_code = ((a*256 + b)*256 +c)*256 + d pid_bits = split_bits(merged_code, 32) pids = [] for i, b in enumerate(pid_bits): if b == 1: pids.append(i+1+offset) return pids
def test_usb_crc16(self): import ripyl.util.bitops as bitops self.test_name = 'USB CRC-16' self.trial_count = 1000 for i in xrange(self.trial_count): self.update_progress(i+1) data_size = random.randint(1,30) data = [random.randint(0,255) for _ in xrange(data_size)] b_data = [] for d in data: b_data.extend(reversed(bitops.split_bits(d, 8))) crc16 = bitops.join_bits(reversed(usb.usb_crc16(b_data))) tcrc16 = bitops.join_bits(reversed(usb.table_usb_crc16(data))) if crc16 != tcrc16: print('\nMismatch: {}, {}, {}, {}'.format(hex(crc16), hex(tcrc16), hex(ncrc16), data)) self.assertEqual(crc16, tcrc16, 'CRC-16 mismatch')
def test_usb_crc16(self): import ripyl.util.bitops as bitops self.test_name = 'USB CRC-16' self.trial_count = 1000 for i in xrange(self.trial_count): self.update_progress(i + 1) data_size = random.randint(1, 30) data = [random.randint(0, 255) for _ in xrange(data_size)] b_data = [] for d in data: b_data.extend(reversed(bitops.split_bits(d, 8))) crc16 = bitops.join_bits(reversed(usb.usb_crc16(b_data))) tcrc16 = bitops.join_bits(reversed(usb.table_usb_crc16(data))) if crc16 != tcrc16: print('\nMismatch: {}, {}, {}, {}'.format( hex(crc16), hex(tcrc16), hex(ncrc16), data)) self.assertEqual(crc16, tcrc16, 'CRC-16 mismatch')
def _get_status(a, b, c, d): '''Decode response for sid 0x01, pid 0x01''' r = {} r['DTC count'] = a & 0x7F r['MIL status'] = True if a & 0x80 else False r['spark ignition'] = False if b & 0x08 else True test_available = [bool(v) for v in split_bits(b & 0x07, 3)] test_incomplete = [bool(v) for v in split_bits((b & 0x70) >> 4, 3)] common_tests = ['misfire', 'fuel system', 'components'] tests = {} for tname, ta, tc in zip(common_tests, test_available, test_incomplete): #print('## test', tname, ta, tc) tests[tname] = (ta, tc) if r['spark ignition']: spark_tests = ['catalyst', 'heated catalyst', 'evap. system', \ 'secondary air system', 'A/C refrigerant', 'oxygen sensor', \ 'oxygen sensor heater', 'EGR system'] test_available = [bool(v) for v in split_bits(c, 8)] test_incomplete = [bool(v) for v in split_bits(d, 8)] #print('## ta', test_available, test_complete) for tname, ta, tc in zip(spark_tests, test_available, test_incomplete): #print('## test', tname, ta, tc) tests[tname] = (ta, tc) else: #compression compression_tests = [('NMHC cat', 0), ('NOx/SCR meter', 1), ('boost pressure', 3), \ ('exhaust gas sensor', 5), ('PM filter monitoring', 6), ('EGR and/or VVT system', 7)] test_available = [bool(v) for v in reversed(split_bits(c, 8))] test_incomplete = [bool(v) for v in reversed(split_bits(d, 8))] for tname, i in compression_tests: #print('## test', tname, test_available[i], test_incomplete[i]) tests[tname] = (test_available[i], test_incomplete[i]) r['tests'] = tests return r
def nec_synth(messages, idle_start=0.0, message_interval=42.5e-3, idle_end=1.0e-3): '''Generate synthesized NEC Infrared waveforms This function simulates NEC IR pulses. messages (sequence of NECMessage) Commands to be synthesized. idle_start (float) The amount of idle time before the transmission of messages begins. message_interval (float) The amount of time between messages. idle_end (float) The amount of idle time after the last message. Yields an edge stream of (float, int) pairs. The first element in the iterator is the initial state of the stream. ''' t = 0.0 irtx = 0 # idle-low yield (t, irtx) # set initial conditions; idle-low t += idle_start for msg in messages: irtx = 1 # start AGC burst yield (t, irtx) t += 9.0e-3 # 9ms irtx = 0 yield (t, irtx) if msg.cmd == -1 and msg.addr_low == -1: # this is a repeat message t += 2.25e-3 # 2.25ms else: # command message t += 4.5e-3 # 4.5ms msg_bytes = (split_bits(msg.addr_low, 8), split_bits(msg.addr_high, 8), \ split_bits(msg.cmd, 8), split_bits(~msg.cmd, 8)) msg_bits = [bit for b in msg_bytes for bit in reversed(b)] for bit in msg_bits: # output initial 560us pulse irtx = 1 yield (t, irtx) t += 560.0e-6 irtx = 0 yield (t, irtx) if bit == 1: t += 2.25e-3 - 560.0e-6 else: t += 1.12e-3 - 560.0e-6 # output stop pulse irtx = 1 yield (t, irtx) t += 560.0e-6 irtx = 0 yield (t, irtx) t += message_interval t += idle_end - message_interval yield (t, irtx)
def rc6_synth(messages, idle_start=0.0, message_interval=89.0e-3, idle_end=1.0e-3): '''Generate synthesized RC6 infrared waveforms This function simulates Philips RC6 IR pulses. messages (sequence of RC6Message) Commands to be synthesized. idle_start (float) The amount of idle time before the transmission of messages begins. message_interval (float) The amount of time between messages. idle_end (float) The amount of idle time after the last message. Yields an edge stream of (float, int) pairs. The first element in the iterator is the initial state of the stream. ''' t = 0.0 pulse_width = 444.0e-6 # 444us pulse width yield (t, 0) # set initial conditions; idle-low t += idle_start for msg in messages: msg_bits = [1] # Start bit msg_bits.extend(split_bits(msg.mode, 3)) msg_bits.extend([2, 2]) # Place-holders for the toggle bit if msg.customer is not None and msg.mode == 6: if msg.customer > 127: msg_bits.append(1) # 15-bit customer msg_bits.extend(split_bits(msg.customer, 15)) else: msg_bits.append(0) # 7-bit customer msg_bits.extend(split_bits(msg.customer, 7)) msg_bits.extend(split_bits(msg.addr, 8)) msg_bits.extend(split_bits(msg.cmd, 8)) #print('\n### synth msg_bits:', msg_bits) coded_bits = ((1, 0) if b else (0, 1) for b in msg_bits) # Expand each bit into a pair of half bits coded_bits = [b for sl in coded_bits for b in sl] # Flatten the tuples coded_bits[8:12] = (1, 1, 0, 0) if msg.toggle else (0, 0, 1, 1) # Add toggle bit #print('### synth coded_bits:', coded_bits) coded_bits = [1, 1, 1, 1, 1, 1, 0, 0] + coded_bits # Add AGC leader prev_state = 0 for b in coded_bits: if b != prev_state: yield (t, b) t += pulse_width prev_state = b if prev_state == 1: yield (t, 0) t += message_interval t += idle_end - message_interval yield (t, 0) # Final state
def sirc_synth(messages, idle_start=0.0, message_interval=42.5e-3, idle_end=1.0e-3): '''Generate synthesized Sony SIRC Infrared waveforms This function simulates SIRC IR pulses. messages (sequence of SIRCMessage) Commands to be synthesized. idle_start (float) The amount of idle time before the transmission of messages begins. message_interval (float) The amount of time between messages. idle_end (float) The amount of idle time after the last message. Yields an edge stream of (float, int) pairs. The first element in the iterator is the initial state of the stream. ''' t = 0.0 irtx = 0 # idle-low one_t = 600.0e-6 # 600us 1T time yield (t, irtx) # set initial conditions t += idle_start for msg in messages: msg_bits = list(reversed(split_bits(msg.cmd, 7))) if msg.device < 2**5 or msg.extended is not None: msg_bits.extend(reversed(split_bits(msg.device, 5))) else: # 15-bit command with 8-bit device field msg_bits.extend(reversed(split_bits(msg.device, 8))) if msg.extended is not None: msg_bits.extend(reversed(split_bits(msg.extended, 8))) irtx = 1 # start pulse burst yield (t, irtx) t += 4 * one_t # 4T pulse irtx = 0 yield (t, irtx) for bit in msg_bits: t += one_t # 1T space irtx = 1 yield (t, irtx) t += (bit+1) * one_t # 1T or 2T pulse irtx = 0 yield (t, irtx) t += one_t # 1T space t += message_interval t += idle_end - message_interval yield (t, irtx) # Final state