Return synchronous version of Blackbird interface
    :param port_url: serial port, i.e. '/dev/ttyUSB0'
    :return: synchronous implementation of Blackbird interface

def get_blackbird(url, use_serial=True):
    """
    Return synchronous version of Blackbird interface
    :param port_url: serial port, i.e. '/dev/ttyUSB0'
    :return: synchronous implementation of Blackbird interface
    """
    lock = RLock()
    print(serial)

    def synchronized(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            with lock:
                return func(*args, **kwargs)
        return wrapper

    class BlackbirdSync(Blackbird):
        def __init__(self, url):
            """
            Initialize the client.
            """
            if use_serial:
                self._port = serial.serial_for_url(url, do_not_open=True)
                self._port.baudrate = 9600
                self._port.stopbits = serial.STOPBITS_ONE
                self._port.bytesize = serial.EIGHTBITS
                self._port.parity = serial.PARITY_NONE
                self._port.timeout = TIMEOUT
                self._port.write_timeout = TIMEOUT
                self._port.open()

            else:
                self.host = url
                self.port = PORT
                self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.socket.settimeout(TIMEOUT)
                self.socket.connect((self.host, self.port))

                # Clear login message
                self.socket.recv(SOCKET_RECV)

        def _process_request(self, request: bytes, skip=0):
            """
            Send data to socket
            :param request: request that is sent to the blackbird
            :param skip: number of bytes to skip for end of transmission decoding
            :return: ascii string returned by blackbird
            """
            _LOGGER.debug('Sending "%s"', request)

            if use_serial:
                # clear
                self._port.reset_output_buffer()
                self._port.reset_input_buffer()
                # send
                self._port.write(request)
                self._port.flush()
                # receive
                result = bytearray()
                while True:
                    c = self._port.read(1)
                    if c is None:
                        break
                    if not c:
                        raise serial.SerialTimeoutException(
                            'Connection timed out! Last received bytes {}'.format([hex(a) for a in result]))
                    result += c
                    if len(result) > skip and result [-LEN_EOL:] == EOL:
                        break
                ret = bytes(result)
                _LOGGER.debug('Received "%s"', ret)
                return ret.decode('ascii')

            else:
                self.socket.send(request)

                response = ''

                while True:

                    data = self.socket.recv(SOCKET_RECV)
                    response += data.decode('ascii')
                    
                    if EOL in data and len(response) > skip:
                        break

                return response

        @synchronized
        def zone_status(self, zone: int):
            # Returns status of a zone
            return ZoneStatus.from_string(zone, self._process_request(_format_zone_status_request(zone), skip=20))

        @synchronized
        def set_zone_power(self, zone: int, power: bool):
            # Set zone power
            self._process_request(_format_set_zone_power(zone, power))

        @synchronized
        def set_zone_source(self, zone: int, source: int):
            # Set zone source
            self._process_request(_format_set_zone_source(zone, source))

        @synchronized
        def set_all_zone_source(self, source: int):
            # Set all zones to one source
            self._process_request(_format_set_all_zone_source(source))

        @synchronized
        def lock_front_buttons(self):
            # Lock front panel buttons
            self._process_request(_format_lock_front_buttons())

        @synchronized
        def unlock_front_buttons(self):
            # Unlock front panel buttons
            self._process_request(_format_unlock_front_buttons())

        @synchronized
        def lock_status(self):
            # Report system locking status
            return LockStatus.from_string(self._process_request(_format_lock_status()))

    return BlackbirdSync(url)