def do_send_recvs(self): meter_packet = np.zeros(METERING_PACKET_SIZE, dtype=np.float64) first_meter_index_needed = 0 while True: dirty = self._param_mem_dirty.nonzero()[0] meter_words_desired = METERING_PACKET_SIZE - first_meter_index_needed if len(dirty) == 0: if meter_words_desired <= 0: # All sending and receiving this time is complete. break # Otherwise, pick a random address to start from first_param_send_index = random.randrange(max(0, len(self._param_mem_contents) - self.spi_words)) else: first_param_send_index = dirty[0] param_data_to_send = self._param_mem_contents[first_param_send_index:] if len(param_data_to_send) > self.spi_words: param_data_to_send = param_data_to_send[: self.spi_words] words_in_transfer = len(param_data_to_send) read_buf = self._read_buf[:words_in_transfer] # Unpack floats into fixed point in the write buffer. write_buf = self._write_buf[:words_in_transfer] wireformat.floats_to_fixeds(param_data_to_send, PARAM_INT_BITS, PARAM_FRAC_BITS, write_buf.view(np.int64)) # print '{} @ rd: {} wr: {}'.format(words_in_transfer, first_meter_index_needed, first_param_send_index) self.spi_channel.transfer( read_addr=first_meter_index_needed, read_data=read_buf, write_addr=first_param_send_index, write_data=write_buf, ) # Mark param memory segment not dirty. self._param_mem_dirty[first_param_send_index : first_param_send_index + words_in_transfer] = 0 # Extract the metering data we got. meter_vals_read = read_buf[:meter_words_desired] wireformat.sign_extend(meter_vals_read, METER_SIGN_BIT) wireformat.fixeds_to_floats( meter_vals_read.view(np.int64), METER_FRAC_BITS, meter_packet[first_meter_index_needed : first_meter_index_needed + len(meter_vals_read)], ) # TODO: wraparound, since the meter data at the beginning of the packet is going to be newer. first_meter_index_needed += words_in_transfer break # FIXME. self._meter_revision += 1 np.maximum(2 ** -METER_FRAC_BITS, meter_packet, out=meter_packet) # meter packet contains LPF of square of signal value right-shifted by 2 bits. # So: correct for the shift, correct for the crest factor, sqrt, and convert to dB. meter_values = 20 * np.log10(np.sqrt(meter_packet * 2 ** 2 * 2)) self._meter_mem_contents = (self._meter_revision, meter_values)
def test_signextend(): unsigned_vals = np.array([0x0, 0x1, 0xf, 0x8], dtype=np.uint64) ref = np.array([0, 1, -1, -8], dtype=np.int64) wireformat.sign_extend(unsigned_vals, 3) assert np.all(unsigned_vals.view(np.int64) == ref)