1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
|
# -*- coding: utf-8 -*-
"""Common tools.
This code is currently taken from PyVISA-py.
Do not edit here.
:copyright: 2014-2022 by PyVISA-sim Authors, see AUTHORS for more details.
:license: MIT, see LICENSE for more details.
"""
import logging
from typing import Callable, Iterator, Optional, Sequence
from pyvisa import logger
logger = logging.LoggerAdapter(logger, {"backend": "sim"}) # type: ignore
def _create_bitmask(bits: int) -> int:
"""Create a bitmask for the given number of bits."""
mask = (1 << bits) - 1
return mask
def iter_bytes(
data: bytes, data_bits: Optional[int] = None, send_end: Optional[bool] = None
) -> Iterator[bytes]:
"""Clip values to the correct number of bits per byte.
Serial communication may use from 5 to 8 bits.
Parameters
----------
data : The data to clip as a byte string.
data_bits : How many bits per byte should be sent. Clip to this many bits.
For example: data_bits=5: 0xff (0b1111_1111) --> 0x1f (0b0001_1111).
Acceptable range is 5 to 8, inclusive. Values above 8 will be clipped to 8.
This maps to the VISA attribute VI_ATTR_ASRL_DATA_BITS.
send_end :
If None (the default), apply the mask that is determined by data_bits.
If False, apply the mask and set the highest (post-mask) bit to 0 for
all bytes.
If True, apply the mask and set the highest (post-mask) bit to 0 for
all bytes except for the final byte, which has the highest bit set to 1.
References
----------
+ https://www.ivifoundation.org/downloads/Architecture%20Specifications/vpp43_2022-05-19.pdf,
+ https://www.ni.com/docs/en-US/bundle/ni-visa/page/ni-visa/vi_attr_asrl_data_bits.html,
+ https://www.ni.com/docs/en-US/bundle/ni-visa/page/ni-visa/vi_attr_asrl_end_out.html
"""
if send_end and data_bits is None:
raise ValueError("'send_end' requires a valid 'data_bits' value.")
if data_bits is None:
for d in data:
yield bytes([d])
else:
if data_bits <= 0:
raise ValueError("'data_bits' cannot be zero or negative")
if data_bits > 8:
data_bits = 8
if send_end is None:
# only apply the mask
mask = _create_bitmask(data_bits)
for d in data:
yield bytes([d & mask])
elif bool(send_end) is False:
# apply the mask and set highest bits to 0
# This is effectively the same has reducing the mask by 1 bit.
mask = _create_bitmask(data_bits - 1)
for d in data:
yield bytes([d & mask])
elif bool(send_end) is True:
# apply the mask and set highest bits to 0
# This is effectively the same has reducing the mask by 1 bit.
mask = _create_bitmask(data_bits - 1)
for d in data[:-1]:
yield bytes([d & mask])
# except for the last byte which has it's highest bit set to 1.
last_byte = data[-1]
highest_bit = 1 << (data_bits - 1)
yield bytes([(last_byte & mask) | highest_bit])
else:
raise ValueError(f"Unknown 'send_end' value '{send_end}'")
int_to_byte: Callable[[int], bytes] = lambda val: bytes([val])
last_int: Callable[[Sequence[int]], int] = lambda val: val[-1]
|