Ejemplo n.º 1
0
    def __init__(self, **params):
        super().__init__()

        self.id = 'chT'
        self.params = params

        portname = params.get('portname', '/dev/ttyUSB0')
        baudrate = params.get('baudrate', 50)
        bytesize = params.get('bytesize', 5)
        stopbits = params.get('stopbits', serial.STOPBITS_ONE_POINT_FIVE)
        coding = params.get('coding', 0)
        loopback = params.get('loopback', None)
        self._local_echo = params.get('loc_echo', False)

        self._rx_buffer = []
        self._tx_buffer = []
        self._counter_LTRS = 0
        self._counter_FIGS = 0
        self._counter_dial = 0
        self._time_last_dial = 0
        self._cts_stable = True  # rxd=Low
        self._cts_counter = 0
        self._time_squelch = 0
        self._is_enabled = False
        self._is_online = False
        self._last_out_waiting = 0

        self._set_mode(params['mode'])
        if loopback is not None:
            self._loopback = loopback

        self._inverse_dtr = params.get('inverse_dtr', self._inverse_dtr)
        self._inverse_rts = params.get('inverse_rts', self._inverse_rts)

        # init serial
        self._tty = serial.Serial(portname, write_timeout=0)

        if baudrate not in self._tty.BAUDRATES:
            raise Exception('Baudrate not supported')
        if bytesize not in self._tty.BYTESIZES:
            raise Exception('Databits not supported')
        if stopbits not in self._tty.STOPBITS:
            raise Exception('Stopbits not supported')

        self._tty.baudrate = baudrate
        self._tty.bytesize = bytesize
        self._tty.stopbits = stopbits
        self._baudrate = baudrate

        # init codec
        #character_duration = (bytesize + 1.0 + stopbits) / baudrate
        character_duration = (
            bytesize + 3.0) / baudrate  # CH340 sends always with 2 stop bits
        self._mc = txCode.BaudotMurrayCode(
            self._loopback,
            coding=coding,
            character_duration=character_duration)

        self._set_enable(False)
        self._set_online(False)
Ejemplo n.º 2
0
    def read_file(self, file_name: str):
        base_name = os.path.join('read', file_name.lower())
        try:
            name = self.read_file_exist(base_name, ('txt', ))
            text = ''

            if name:
                with open(name, mode="r", encoding="utf-8") as fp:
                    text = fp.read()
                    text = text.replace('\n', '\r\n')
                    text = txCode.BaudotMurrayCode.translate(text)

            name = self.read_file_exist(base_name, ('pix', 'pox'))
            if name:
                with open(name, 'rb') as fp:
                    text = fp.read().decode('ASCII', errors='ignore')
                    for us, eu in (('&', '8'), ('#', 'M'), ('$', 'S'),
                                   ('"', "'"), (';', ','), ('!', '1'), ('\x1A',
                                                                        '')):
                        text = text.replace(us, eu)
                    text = txCode.BaudotMurrayCode.translate(text)
                    if True:
                        mc = txCode.BaudotMurrayCode()
                        bintext = mc.encodeA2BM(text)
                        with open(base_name + '_.bin', 'wb') as wfp:
                            wfp.write(bintext)

            name = self.read_file_exist(base_name, ('bin', 'ls'))
            if name:
                with open(name, 'rb') as fp:
                    bintext = fp.read()
                    mc = txCode.BaudotMurrayCode(flip_bits=name.endswith('ls'))
                    text = mc.decodeBM2A(bintext)

            if text:
                self._rx_buffer.extend(list(text))
                l.info("Read file: {!r} ({} chars)".format(name, len(text)))

        except:
            l.error("Error in read file")
Ejemplo n.º 3
0
    def __init__(self, **params):
        super().__init__()

        self._mc = txCode.BaudotMurrayCode()

        self.id = '='
        self.params = params

        self._tx_buffer = []

        self.run = True
        self._tx_thread = Thread(target=self.thread_tx)
        self._tx_thread.start()
Ejemplo n.º 4
0
    def __init__(self, **params):
        super().__init__()

        self._mc = txCode.BaudotMurrayCode(loop_back=False)

        self.id = 'edS'
        self.params = params

        self._tx_buffer = []
        self._rx_buffer = []
        self._is_online = Event()
        self._ST_pressed = False
        # State of rx thread, governs most of the module operation. States:
        # -  0 offline / startup
        # - 10 going online by ESC-WB/-A
        # - 20 online
        # - 30 going offline by ESC-Z
        # - 40 offline delay after buffer is empty
        # - 50 offline, wait for A level
        self._rx_state = 0

        # Helper variables for printer feedback
        self._last_tx_buf_len = 0
        self._send_feedback = False

        self.recv_squelch = self.params.get('recv_squelch', 100)
        self.recv_debug = self.params.get('recv_debug', False)
        self.send_WB_pulse = self.params.get('send_WB_pulse', False)

        recv_f0 = self.params.get('recv_f0', 2250)
        recv_f1 = self.params.get('recv_f1', 3150)
        recv_f = [recv_f0, recv_f1]
        self._recv_decode_init(recv_f)

        # Save how many characters have been printed per session
        self.printed_chars = 0

        self._run = True
        self._tx_thread = Thread(target=self.thread_tx, name='ED1000tx')
        self._tx_thread.start()
        self._rx_thread = Thread(target=self.thread_rx, name='ED1000rx')
        self._rx_thread.start()
Ejemplo n.º 5
0
    def __init__(self, **params):
        super().__init__()

        self._mc = txCode.BaudotMurrayCode()

        self.id = '='
        self.params = params

        self._txb_buffer = []
        self._rxb_buffer = []
        self._carrier_counter = 0
        self._carrier_detected = False

        self.do_plot()

        self.run = True
        #self._tx_thread = Thread(target=self.thread_tx)
        #self._tx_thread.start()
        self._rx_thread = Thread(target=self.thread_rx)
        self._rx_thread.start()
Ejemplo n.º 6
0
    def __init__(self, **params):
        super().__init__()

        self._mc = txCode.BaudotMurrayCode(loop_back=False)

        self.id = 'edS'
        self.params = params

        self._tx_buffer = []
        self._rx_buffer = []
        self._is_online = Event()
        self._ST_pressed = False
        # State of rx thread, governs most of the module operation (see class
        # ST)
        self._rx_state = ST.OFFLINE

        # Helper variables for printer feedback
        self._last_tx_buf_len = 0
        self._send_feedback = False

        self.recv_squelch = self.params.get('recv_squelch', 100)
        self.recv_debug = self.params.get('recv_debug', False)
        self.send_WB_pulse = self.params.get('send_WB_pulse', False)
        self.unres_threshold = self.params.get('unres_threshold', 100)

        recv_f0 = self.params.get('recv_f0', 2250)
        recv_f1 = self.params.get('recv_f1', 3150)
        recv_f = [recv_f0, recv_f1]
        self._recv_decode_init(recv_f)

        # Save how many characters have been printed per session
        self.printed_chars = 0

        # Track MCP active state for printer start feedback
        self._MCP_active = False

        self._run = True
        self._tx_thread = Thread(target=self.thread_tx, name='ED1000tx')
        self._tx_thread.start()
        self._rx_thread = Thread(target=self.thread_rx, name='ED1000rx')
        self._rx_thread.start()
Ejemplo n.º 7
0
    def __init__(self, **params):
        super().__init__()

        self._mc = txCode.BaudotMurrayCode(loop_back=False)

        self.id = '='
        self.params = params

        self._tx_buffer = []
        self._rx_buffer = []
        self._is_online = False

        recv_f0 = self.params.get('recv_f0', 2250)
        recv_f1 = self.params.get('recv_f1', 3150)
        recv_f = [recv_f0, recv_f1]

        self._recv_decode_init(recv_f)

        self.run = True
        self._tx_thread = Thread(target=self.thread_tx, name='ED1000tx')
        self._tx_thread.start()
        self._rx_thread = Thread(target=self.thread_rx, name='ED1000rx')
        self._rx_thread.start()
Ejemplo n.º 8
0
    def process_connection(self, s: socket.socket, is_server: bool,
                           is_ascii: bool):  # Takes client socket as argument.
        """Handles a client or server connection."""
        bmc = txCode.BaudotMurrayCode(False, False, True)
        sent_counter = 0
        self._received_counter = 0
        printed_counter = 0
        timeout_counter = -1
        time_next_send = None
        error = False

        s.settimeout(0.2)

        self._connected = ST.CON_INIT

        # Store remote protocol version to control negotiation
        self._remote_protocol_ver = None

        # Connection type hinting and detection
        if is_ascii is None:
            l.info('Connection hint: auto-detect enabled')
        elif is_ascii:
            l.info('Connection hint: ASCII connection')
        else:
            l.info('Connection hint: i-Telex connection')

        # New printer feedback based on ESC-~
        #
        # Overview:
        # - i-Telex requires us to periodically send Acknowledge packets so
        #   that the sending party can determine how much of the sent data has
        #   been printed already. Its payload is an 8 bit monotonic counter of
        #   undefined reference point. It should however be 0 as soon as we're
        #   ready to receive and print data.
        #
        # - Basic function: We count data received from remote and subtract
        #   current printer buffer contents. Special care is taken to keep the
        #   counter monotonically increasing, which otherwise might happen if
        #   other modules than us also send data to the printer.

        # If we're server, use negative Acknowledge counter first to allow for
        # fixed-length welcome banner printing
        self._acknowledge_counter = self._last_acknowledge_counter = (
            -24 if is_server else 0
        )  # fixed length of welcome banner, see txDevMCP

        # The rationale here is to, after starting the printer, first print the
        # complete welcome banner. Received data must only by printed *after*
        # this.
        #
        # The typical sequence is as follows:
        #
        # - After printable data is received for the first time, we decide on
        #   the connection type (Baudot or ASCII), queue some commands (start
        #   printer, MCP output welcome banner) and also queue the received
        #   data afterwards. (state 2)
        #
        # - Main loop read()-s us. Our read method is filtered (based on state
        #   2) so that only commands are read, printable data is retained for
        #   later perusal.
        #
        # - Eventually, MCP receives the welcome banner command. It sends the
        #   banner, which is writ[e]()-ten to us. After the banner, it sends
        #   the ESC-WELCOME command which tells us the banner has been written
        #   completely. On this command, our read method is unlocked and
        #   previously received data is available for main loop. (state 4)

        # Start with ST.DISCON to trigger log message
        _connected_before = ST.DISCON
        while self._connected > ST.DISCON:
            if _connected_before != self._connected:
                l.info("State transition: {!s}=>{!s}".format(
                    _connected_before, self._connected))
                _connected_before = self._connected
                # We just entered ST.CON_TP_RUN (printer running, waiting for
                # welcome banner)
                if self._connected == ST.CON_TP_RUN:
                    if is_server:
                        # Send welcome banner
                        self._tx_buffer = []
                        self.send_welcome(s)
                    else:
                        # We're client: skip ST.CON_TP_RUN
                        self._connected = ST.CON_FULL
                        continue
                elif self._connected == ST.CON_FULL:
                    # Send first Acknowledge
                    if not is_ascii:
                        # Send fixed value in Acknowledge packet, mainly for
                        # server case (24 characters of welcome banner have to
                        # be printed before anything else). Typically, the
                        # welcome banner hasn't yet reached the printer buffer,
                        # which would lead to sending 0 instead of -24.
                        #
                        # The next timed Acknowledge will be sent with a filled
                        # printer buffer in most cases. If not, the damage
                        # should be manageable.
                        #
                        # (This problem results from the non-deterministic
                        # sequence with the current piTelex architecture,
                        # namely multiple threads and message passing in a
                        # central loop, and can be solved best by a major
                        # restructuring.)
                        self.send_ack(
                            s,
                            (-24 if is_server else 0
                             ))  # fixed length of welcome banner, see txDevMCP

            try:
                data = s.recv(1)

                # piTelex terminates; close connection
                if not self._run:
                    break

                # lost connection
                if not data:
                    l.warning("Remote has closed connection")
                    break

                # Telnet control sequence
                elif data[0] == 255:
                    d = s.recv(2)  # skip next 2 bytes from telnet command

                # i-Telex packet
                elif data[0] in allowed_types():
                    packet_error = False

                    d = s.recv(1)
                    data += d
                    packet_len = d[0]
                    if packet_len:
                        data += s.recv(packet_len)

                    # Heartbeat
                    if data[0] == 0 and packet_len == 0:
                        l.debug(
                            'Received i-Telex packet: Heartbeat ({})'.format(
                                display_hex(data)))

                    # Direct Dial
                    elif data[0] == 1 and packet_len == 1:
                        l.debug(
                            'Received i-Telex packet: Direct dial ({})'.format(
                                display_hex(data)))

                        # Disable emitting "direct dial" command, since it's
                        # currently not acted upon anywhere.
                        #self._rx_buffer.append('\x1bD'+str(data[2]))

                        # Instead, only accept extension 0 (i-Telex default)
                        # and None, and reject all others.
                        ext = decode_ext_from_direct_dial(data[2])
                        l.info('Direct Dial, extension {}'.format(ext))
                        if not ext in ('0', None):
                            self.send_reject(s, 'na')
                            error = True
                            break
                        else:
                            if self._connected == ST.CON_INIT:
                                if not self._printer_running:
                                    # Request printer start; confirmation will
                                    # arrive as ESC-~ (write method will
                                    # advance to ST.CON_TP_RUN and do what's in
                                    # the following else block)
                                    self._connected = ST.CON_TP_REQ
                                    self._rx_buffer.append('\x1bA')
                                else:
                                    # Printer already running; welcome banner
                                    # will be sent above in next iteration if
                                    # we're server
                                    self._connected = ST.CON_TP_RUN
                                    self._rx_buffer.append('\x1bA')

                    # Baudot Data
                    elif data[0] == 2 and packet_len >= 1 and packet_len <= 50:
                        l.debug(
                            'Received i-Telex packet: Baudot data ({})'.format(
                                display_hex(data)))
                        aa = bmc.decodeBM2A(data[2:])
                        if self._connected == ST.CON_INIT:
                            if not self._printer_running:
                                # Request printer start; confirmation will
                                # arrive as ESC-~ (write method will
                                # advance to ST.CON_TP_RUN and do what's in
                                # the following else block)
                                self._connected = ST.CON_TP_REQ
                                self._rx_buffer.append('\x1bA')
                            else:
                                # Printer already running; welcome banner
                                # will be sent above in next iteration if
                                # we're server
                                self._connected = ST.CON_TP_RUN
                                self._rx_buffer.append('\x1bA')
                        for a in aa:
                            if a == '@':
                                a = '#'
                            self._rx_buffer.append(a)
                        self._received_counter += len(data[2:])
                        # Send Acknowledge if printer is running and we've got
                        # at least 16 characters left to print
                        if self._connected >= ST.CON_FULL and self._print_buf_len >= 16:
                            self.send_ack(s, self._acknowledge_counter)

                    # End
                    elif data[0] == 3 and packet_len == 0:
                        l.debug('Received i-Telex packet: End ({})'.format(
                            display_hex(data)))
                        l.info('End by remote')
                        break

                    # Reject
                    elif data[0] == 4 and packet_len <= 20:
                        l.debug('Received i-Telex packet: Reject ({})'.format(
                            display_hex(data)))
                        aa = data[2:].decode('ASCII', errors='ignore')
                        # i-Telex may pad with \x00 (e.g. "nc\x00"); remove padding
                        aa = aa.rstrip('\x00')
                        l.info(
                            'i-Telex connection rejected, reason {!r}'.format(
                                aa))
                        aa = bmc.translate(aa)
                        for a in aa:
                            self._rx_buffer.append(a)
                        break

                    # Acknowledge
                    elif data[0] == 6 and packet_len == 1:
                        l.debug(
                            'Received i-Telex packet: Acknowledge ({})'.format(
                                display_hex(data)))
                        # TODO: Fix calculation and prevent overflows, e.g. if
                        # the first ACK is sent with a low positive value. This
                        # might be done by saving the first ACK's absolute
                        # counter value and only doing difference calculations
                        # afterwards.
                        unprinted = (sent_counter - int(data[2])) & 0xFF
                        #if unprinted < 0:
                        #    unprinted += 256
                        l.debug(
                            str(data[2]) + '/' + str(sent_counter) + '=' +
                            str(unprinted) + " (printed/sent=unprinted)")
                        if unprinted < 7:  # about 1 sec
                            time_next_send = None
                        else:
                            time_next_send = time.monotonic() + (unprinted -
                                                                 6) * 0.15
                        # Send Acknowledge if printer is running and remote end
                        # has printed all sent characters
                        # ! Better not, this will create an Ack flood !
                        # if self._connected >= ST.CON_FULL and unprinted == 0:
                        #     self.send_ack(s, self._acknowledge_counter)

                        # Send remote printer buffer feedback
                        self._rx_buffer.append('\x1b^' + str(unprinted))

                    # Version
                    elif data[0] == 7 and packet_len >= 1 and packet_len <= 20:
                        l.debug('Received i-Telex packet: Version ({})'.format(
                            display_hex(data)))
                        if self._remote_protocol_ver is None:
                            if data[2] != 1:
                                # This is the first time an unsupported version was offered
                                l.warning(
                                    "Unsupported version offered by remote ({}), requesting v1"
                                    .format(display_hex(data[2:])))
                                self.send_version(s)
                            else:
                                # Only send version packet in response to valid
                                # version when we're server, because as client,
                                # we sent a version packet directly after
                                # connecting.
                                if is_server:
                                    self.send_version(s)
                            # Store offered version
                            self._remote_protocol_ver = data[2]
                        else:
                            if data[2] != 1:
                                # The remote station insists on incompatible
                                # version. Send the not-officially-defined
                                # error code "ver".
                                l.error(
                                    "Unsupported version insisted on by remote ({})"
                                    .format(display_hex(data[2:])))
                                self.send_reject(s, 'ver')
                                error = True
                                break
                            else:
                                if data[2] != self._remote_protocol_ver:
                                    l.info(
                                        "Negotiated protocol version {}, initial request was {}"
                                        .format(data[2],
                                                self._remote_protocol_ver))
                                    self._remote_protocol_ver = data[2]
                                else:
                                    # Ignore multiple good version packets
                                    l.info("Redundant Version packet")

                    # Self test
                    elif data[0] == 8 and packet_len >= 2:
                        l.debug(
                            'Received i-Telex packet: Self test ({})'.format(
                                display_hex(data)))

                    # Remote config
                    elif data[0] == 9 and packet_len >= 3:
                        l.info('Received i-Telex packet: Remote config ({})'.
                               format(display_hex(data)))

                    # Wrong packet - will resync at next socket.timeout
                    else:
                        l.warning('Received invalid i-Telex Packet: {}'.format(
                            display_hex(data)))
                        packet_error = True

                    if not packet_error:
                        if is_ascii is None:
                            l.info('Detected i-Telex connection')
                            is_ascii = False
                        elif is_ascii:
                            l.warning(
                                'Detected i-Telex connection, but ASCII was expected'
                            )
                            is_ascii = False

                    # Also send Acknowledge packet if triggered by idle function
                    if self._send_acknowledge_idle:
                        self._send_acknowledge_idle = False
                        self.send_ack(s, self._acknowledge_counter)

                # ASCII character(s)
                else:
                    l.debug('Received non-i-Telex data: {} ({})'.format(
                        repr(data), display_hex(data)))
                    if is_ascii is None:
                        l.info('Detected ASCII connection')
                        is_ascii = True
                    elif not is_ascii:
                        l.warning(
                            'Detected ASCII connection, but i-Telex was expected'
                        )
                        is_ascii = True
                    if self._connected == ST.CON_INIT:
                        if not self._printer_running:
                            # Request printer start; confirmation will
                            # arrive as ESC-~ (write method will
                            # advance to ST.CON_TP_RUN and do what's in
                            # the following else block)
                            self._connected = ST.CON_TP_REQ
                            self._rx_buffer.append('\x1bA')
                        else:
                            # Printer already running; welcome banner
                            # will be sent above in next iteration if
                            # we're server
                            self._connected = ST.CON_TP_RUN
                            self._rx_buffer.append('\x1bA')
                    data = data.decode('ASCII', errors='ignore').upper()
                    data = txCode.BaudotMurrayCode.translate(data)
                    for a in data:
                        if a == '@':
                            a = '#'
                        self._rx_buffer.append(a)
                        self._received_counter += 1

            except socket.timeout:
                #l.debug('.')
                if is_server and self.printer_start_timed_out:
                    self.printer_start_timed_out = False
                    if is_ascii:
                        s.sendall(b"der")
                    else:
                        self.send_reject(s, "der")
                    l.error(
                        "Disconnecting client because printer didn't start up")
                    error = True
                    break
                if is_ascii is not None:  # either ASCII or baudot connection detected
                    timeout_counter += 1

                    if is_ascii:
                        if self._tx_buffer:
                            sent = self.send_data_ascii(s)
                            sent_counter += sent

                    else:  # baudot
                        if (timeout_counter % 5) == 0:  # every 1 sec
                            # Send Acknowledge if printer is running
                            if self._connected >= ST.CON_FULL:
                                self.send_ack(s, self._acknowledge_counter)

                        if self._tx_buffer:
                            if time_next_send and time.monotonic(
                            ) < time_next_send:
                                l.debug('Sending paused for {:.3f} s'.format(
                                    time_next_send - time.monotonic()))
                                pass
                            else:
                                sent = self.send_data_baudot(s, bmc)
                                sent_counter += sent
                                if sent > 7:
                                    time_next_send = time.monotonic() + (
                                        sent - 6) * 0.15

                        elif (timeout_counter % 15) == 0:  # every 3 sec
                            #self.send_heartbeat(s)
                            pass
                            # Suppress Heartbeat for now
                            #
                            # Background: The spec and personal conversation
                            # with Fred yielded that i-Telex uses Heartbeat
                            # only until the printer has been started. After
                            # that, only Acknowledge is used.
                            #
                            # Complications arise from the fact that some
                            # services in the i-Telex network interpret
                            # Heartbeat just like Acknowledge, i.e. printer is
                            # started and printer buffer empty. Special case is
                            # the 11150 service, which in the current version,
                            # on receiving Heartbeat, sends a WRU whilst the
                            # welcome banner is being printed, causing a
                            # character jumble.

            except socket.error:
                l.error("Exception caught:", exc_info=sys.exc_info())
                error = True
                break

        if not is_ascii:
            # Don't send end packet in case of error. There may be two error
            # cases:
            # - Protocol error: We've already sent a reject package.
            # - Network error: There's no connection to send over anymore.
            if not error:
                self.send_end(s)
        l.info('end connection')
        self._connected = ST.DISCON
        if _connected_before != self._connected:
            l.info("State transition: {!s}=>{!s}".format(
                _connected_before, self._connected))
Ejemplo n.º 9
0
    def thread_srv_handle_client(self, client):  # Takes client socket as argument.
        """Handles a single client connection."""
        bmc = txCode.BaudotMurrayCode(False, False, True)
        is_ascii = None   # not known yet

        client.settimeout(0.2)

        self._rx_buffer.append('\x1bA')

        while self.run:
            try:
                data = client.recv(1)
                
                if not data:   # lost connection
                    break

                elif data[0] < 0x10:   # i-Telex packet
                    if is_ascii is None:
                        self.send_welcome(client)
                    is_ascii = False
                    d = client.recv(1)
                    data += d
                    plen = d[0]
                    data += client.recv(plen)

                    if data[0] == 0:   # Heartbeat
                        #LOG('Heartbeat '+repr(data), 4)
                        pass

                    elif data[0] == 1:   # Direct Dial
                        LOG('Direct Dial '+repr(data), 4)
                        self._rx_buffer.append('\x1bD'+str(data[2]))

                    elif data[0] == 2 and plen > 0:   # Baudot data
                        #LOG('Baudot data '+repr(data), 4)
                        aa = bmc.decodeBM2A(data[2:])
                        for a in aa:
                            if a == '@':
                                a = '#'
                            self._rx_buffer.append(a)
                        self._received += len(data[2:])
                        self.send_ack(client)

                    elif data[0] == 3:   # End
                        LOG('End '+repr(data), 4)
                        break

                    elif data[0] == 4:   # Reject
                        LOG('Reject '+repr(data), 4)
                        break

                    elif data[0] == 6 and plen == 1:   # Acknowledge
                        #LOG('Acknowledge '+repr(data), 4)
                        LOG(str(data[2]))
                        pass

                    elif data[0] == 7 and plen >= 1:   # Version
                        #LOG('Version '+repr(data), 4)
                        self.send_version(client)

                    elif data[0] == 8:   # Self test
                        LOG('Self test '+repr(data), 4)
                        pass

                    elif data[0] == 9:   # Remote config
                        LOG('Remote config '+repr(data), 4)
                        pass

                else:   # ASCII character(s)
                    #LOG('Other', repr(data), 4)
                    if is_ascii is None:
                        self.send_welcome(client)
                    is_ascii = True
                    data = data.decode('ASCII', errors='ignore').upper()
                    data = txCode.BaudotMurrayCode.translate(data)
                    for a in data:
                        if a == '@':
                            a = '#'
                        self._rx_buffer.append(a)
                        self._received += 1


            except socket.timeout:
                #LOG('.', 4)
                if is_ascii is not None:
                    if self._tx_buffer:
                        if is_ascii:
                            self.send_data_ascii(client)
                        else:
                            self.send_data_baudot(client, bmc)
                    else:
                        if not is_ascii:
                            self.send_heartbeat(client)
                    

            except socket.error:
                LOG('Error socket', 2)
                break


        LOG('end connection', 3)
        client.close()
        del self.clients[client]
        self._rx_buffer.append('\x1bZ')
        pass
Ejemplo n.º 10
0
    def process_connection(self, s: socket.socket, is_server: bool,
                           is_ascii: bool):  # Takes client socket as argument.
        """Handles a client or server connection."""
        bmc = txCode.BaudotMurrayCode(False, False, True)
        sent_counter = 0
        received_counter = 0
        timeout_counter = -1
        time_next_send = None

        s.settimeout(0.2)

        self._connected = True

        while self._connected:
            try:
                data = s.recv(1)

                # lost connection
                if not data:
                    break

                # Telnet control sequence
                elif data[0] == 255:
                    d = s.recv(2)  # skip next 2 bytes from telnet command

                # i-Telex packet
                elif data[0] < 10:
                    packet_error = False

                    d = s.recv(1)
                    data += d
                    packet_len = d[0]
                    if packet_len:
                        data += s.recv(packet_len)

                    # Heartbeat
                    if data[0] == 0 and packet_len == 0:
                        #LOG('Heartbeat '+repr(data), 4)
                        pass

                    # Direct Dial
                    elif data[0] == 1 and (1 <= packet_len <= 10):
                        LOG('Direct Dial ' + repr(data), 4)
                        if packet_len >= 5:
                            id = (data[3] << 24) | (data[4] << 16) | (
                                data[5] << 8) | (data[6])
                            print(id)
                        self._rx_buffer.append('\x1bD' + str(data[2]))
                        self.send_ack(s, received_counter)

                    # Baudot Data
                    elif data[0] == 2 and packet_len >= 1 and packet_len <= 50:
                        #LOG('Baudot data '+repr(data), 4)
                        aa = bmc.decodeBM2A(data[2:])
                        for a in aa:
                            if a == '@':
                                a = '#'
                            self._rx_buffer.append(a)
                        received_counter += len(data[2:])
                        self.send_ack(s, received_counter)

                    # End
                    elif data[0] == 3 and packet_len == 0:
                        LOG('End ' + repr(data), 4)
                        break

                    # Reject
                    elif data[0] == 4 and packet_len <= 20:
                        LOG('Reject ' + repr(data), 4)
                        aa = bmc.translate(data[2:])
                        for a in aa:
                            self._rx_buffer.append(a)
                        break

                    # Acknowledge
                    elif data[0] == 6 and packet_len == 1:
                        #LOG('Acknowledge '+repr(data), 4)
                        unprinted = (sent_counter - int(data[2])) & 0xFF
                        #if unprinted < 0:
                        #    unprinted += 256
                        LOG(
                            str(data[2]) + '/' + str(sent_counter) + '=' +
                            str(unprinted), 4)
                        if unprinted < 7:  # about 1 sec
                            time_next_send = None
                        else:
                            time_next_send = time.time() + (unprinted -
                                                            6) * 0.15
                        pass

                    # Version
                    elif data[0] == 7 and packet_len >= 1 and packet_len <= 20:
                        #LOG('Version '+repr(data), 4)
                        if not is_server or data[2] != 1:
                            self.send_version(s)

                    # Self test
                    elif data[0] == 8 and packet_len >= 2:
                        LOG('Self test ' + repr(data), 4)
                        pass

                    # Remote config
                    elif data[0] == 9 and packet_len >= 3:
                        LOG('Remote config ' + repr(data), 4)
                        pass

                    # Wrong packet - will resync at next socket.timeout
                    else:
                        LOG('ERROR Packet ' + repr(data), 3)
                        packet_error = True

                    if not packet_error:
                        is_ascii = False

                # ASCII character(s)
                else:
                    #LOG('Other', repr(data), 4)
                    is_ascii = True
                    data = data.decode('ASCII', errors='ignore').upper()
                    data = txCode.BaudotMurrayCode.translate(data)
                    for a in data:
                        if a == '@':
                            a = '#'
                        self._rx_buffer.append(a)
                        received_counter += 1

            except socket.timeout:
                #LOG('.', 4)
                if is_ascii is not None:  # unknown if ASCII or baudot
                    timeout_counter += 1
                    if is_server and timeout_counter == 1:
                        self._tx_buffer = []
                        self.send_welcome(s)

                    if is_ascii:
                        if self._tx_buffer:
                            sent = self.send_data_ascii(s)
                            sent_counter += sent

                    else:  # baudot
                        if (timeout_counter % 5) == 0:  # every 1 sec
                            self.send_ack(s, received_counter)

                        if self._tx_buffer:
                            if time_next_send and time.time() < time_next_send:
                                LOG(
                                    'Wait' +
                                    str(int(time_next_send - time.time())), 4)
                                pass
                            else:
                                sent = self.send_data_baudot(s, bmc)
                                sent_counter += sent
                                if sent > 7:
                                    time_next_send = time.time() + (sent -
                                                                    6) * 0.15

                        elif (timeout_counter % 15) == 0:  # every 3 sec
                            self.send_heartbeat(s)

            except socket.error:
                LOG('ERROR socket', 2)
                break

        if not is_ascii:
            self.send_end(s)
        LOG('end connection', 3)
        self._connected = False
Ejemplo n.º 11
0
    def __init__(self, **params):
        super().__init__()

        self.id = 'piT'
        self.params = params
        self._timing_tick = 0
        self._time_EOT = 0
        self._last_waiting = 0
        self._state = None
        self._time_squelch = 0
        self._use_squelch = True
        self._keep_alive_counter = 0

        self._tx_buffer = []
        self._rx_buffer = []

        # get setting params

        self._mode = params.get('mode', 'TW39')

        self._baudrate = params.get('baudrate', 50)
        self._bytesize = params.get('bytesize', 5)
        self._stopbits = params.get('stopbits', 1.5)
        self._stopbits2 = int(self._stopbits * 2 + 0.5)

        self._pin_txd = params.get('pin_txd', 17)
        #self._inv_txd = params.get('inv_txd', False)   # not possible with PIGPIO
        self._pin_dir = params.get('pin_dir', 0)
        self._pin_rxd = params.get('pin_rxd', 27)
        self._inv_rxd = params.get('inv_rxd', False)
        self._pin_relay = params.get('pin_relay', 22)
        self._inv_relay = params.get('inv_relay', False)
        self._pin_power = params.get('pin_power', 0)
        self._inv_power = params.get('inv_power', False)
        self._pin_number_switch = params.get(
            'pin_number_switch', params.get('pin_fsg_ns',
                                            6))  # pin typical wired to rxd pin
        self._inv_number_switch = params.get('inv_number_switch', False)

        self._line_observer = None
        if params.get('use_observe_line', True):
            self._pin_observe_line = params.get('pin_observe_line',
                                                self._pin_rxd)
            self._inv_observe_line = params.get('inv_observe_line',
                                                self._inv_rxd)
            self._line_observer = Observer(self._pin_observe_line,
                                           self._inv_observe_line,
                                           10)  # 10ticks = 0.5sec

        self._coding = params.get('coding', 0)
        self._loopback = params.get('loopback', True)
        self._timing_rxd = params.get('timing_rxd', False)
        self._WB_pulse_length = params.get('WB_pulse_length', 40)
        self._double_WR = params.get('double_WR', False)

        # init codec

        self._character_duration = (self._bytesize + 1.0 +
                                    self._stopbits) / self._baudrate
        self._mc = txCode.BaudotMurrayCode(
            self._loopback,
            coding=self._coding,
            character_duration=self._character_duration)

        # init GPIOs

        pi.set_mode(self._pin_rxd, pigpio.INPUT)
        pi.set_pull_up_down(self._pin_rxd, pigpio.PUD_UP)
        pi.set_glitch_filter(self._pin_rxd,
                             50000 // self._baudrate)  # 1ms @ 50Bd

        self._number_switch = None
        if self._pin_number_switch > 0:  # 0:keyboard pos:TW39 neg:TW39@RPiCtrl
            self._number_switch = NumberSwitch(self._pin_number_switch,
                                               self._callback_number_switch,
                                               self._inv_number_switch)

        pi.set_mode(self._pin_txd, pigpio.OUTPUT)
        #pi.write(self._pin_txd, not self._inv_txd)
        pi.write(self._pin_txd, 1)
        if self._pin_power:
            pi.set_mode(self._pin_power, pigpio.OUTPUT)
            pi.write(self._pin_power, self._inv_power)
        if self._pin_relay:
            pi.set_mode(self._pin_relay,
                        pigpio.OUTPUT)  # relay for commutating
            pi.write(self._pin_relay, self._inv_relay)  # pos polarity
        if self._pin_dir:
            pi.set_mode(self._pin_dir,
                        pigpio.OUTPUT)  # direction of comminication
            pi.write(self._pin_dir, 0)  # 1=transmitting

        # init bit bongo serial read

        try:
            _ = pi.bb_serial_read_close(
                self._pin_rxd
            )  # try to close if it is still open from last debug
        except:
            pass
        _ = pi.bb_serial_read_open(self._pin_rxd, self._baudrate,
                                   self._bytesize)
        pi.bb_serial_invert(self._pin_rxd, self._inv_rxd)

        if self._timing_rxd:
            self._cb = pi.callback(self._pin_rxd, pigpio.EITHER_EDGE,
                                   self._callback_timing)

        # init bit bongo serial write

        self.last_wid = None

        # init state

        self._set_state(S_OFFLINE)
Ejemplo n.º 12
0
    def __init__(self, **params):
        super().__init__()

        self._tx_buffer = []
        self._rx_buffer = []
        self._cb = None
        self._is_pulse_dial = False
        self._pulse_dial_count = 0

        self.id = '#'
        self.params = params

        self._baudrate = params.get('baudrate', 50)
        self._bytesize = params.get('bytesize', 5)
        self._stopbits = params.get('stopbits', 1.5)
        self._pin_txd = params.get('pin_txd', 17)
        self._pin_rxd = params.get('pin_rxd', 27)
        self._pin_rel = params.get('pin_rel', 22)
        self._pin_dir = params.get('pin_dir', 11)
        #self._pin_oin = params.get('pin_oin', 10)
        self._pin_opt = params.get('pin_opt', 9)
        #self._pin_sta = params.get('pin_sta', 12)
        self._inv_rxd = params.get('inv_rxd', False)
        #self._inv_txd = params.get('inv_txd', False)
        self._loopback = params.get('loopback', True)
        self._uscoding = params.get('uscoding', True)

        # init codec
        character_duration = (self._bytesize + 1.0 +
                              self._stopbits) / self._baudrate
        self._mc = txCode.BaudotMurrayCode(
            self._loopback,
            us_coding=self._uscoding,
            character_duration=character_duration)

        # init GPIOs
        pi.set_pad_strength(0, 8)

        pi.set_mode(self._pin_rxd, pigpio.INPUT)
        pi.set_pull_up_down(self._pin_rxd, pigpio.PUD_UP)

        pi.set_mode(self._pin_txd, pigpio.OUTPUT)
        #pi.write(self._pin_txd, not self._inv_txd)
        pi.write(self._pin_txd, 1)
        pi.set_mode(self._pin_opt, pigpio.OUTPUT)
        pi.write(self._pin_opt, 0)
        pi.set_mode(self._pin_rel, pigpio.OUTPUT)  # relais for commutating
        pi.write(self._pin_rel, 0)  # pos polarity
        pi.set_mode(self._pin_dir, pigpio.OUTPUT)  # direction of comminication
        pi.write(self._pin_dir, 0)  # 1=transmitting

        # init bit bongo serial read
        pi.set_glitch_filter(self._pin_rxd, 1000)  # 1ms
        status = pi.bb_serial_read_open(self._pin_rxd, self._baudrate,
                                        self._bytesize)  # 50 baud
        pi.bb_serial_invert(self._pin_rxd, self._inv_rxd)

        # init bit bongo serial write
        self.last_wid = None

        # debug
        cbs = pi.wave_get_max_cbs()
        micros = pi.wave_get_max_micros()
        pulses = pi.wave_get_max_pulses()
        pass
Ejemplo n.º 13
0
    def __init__(self, **params):
        super().__init__()

        self.id = '#'
        self.params = params

        self._baudrate = params.get('baudrate', 50)
        self._bytesize = params.get('bytesize', 5)
        self._stopbits = params.get('stopbits', 1.5)
        self._stopbits2 = int(self._stopbits * 2 + 0.5)

        self._pin_txd = params.get('pin_txd', 17)
        self._pin_rxd = params.get('pin_rxd', 27)
        self._pin_fsg_ns = params.get('pin_fsg_ns', 6)  # connected to rxd
        self._pin_rel = params.get('pin_rel', 22)
        self._pin_dir = params.get('pin_dir', 11)
        #self._pin_oin = params.get('pin_oin', 10)
        self._pin_opt = params.get('pin_opt', 9)
        self._pin_sta = params.get('pin_sta', 23)
        self._pin_fsg_at = params.get('pin_fsg_at', 8)  # button AT optional
        self._pin_fsg_st = params.get('pin_fsg_st', 7)  # button ST optional
        self._pin_fsg_lt = params.get('pin_fsg_lt', 0)  # button LT optional
        self._pin_status_r = params.get('pin_status_r', 23)  # LED red
        self._pin_status_g = params.get('pin_status_g', 24)  # LED green

        self._inv_rxd = params.get('inv_rxd', False)
        #self._inv_txd = params.get('inv_txd', False)
        self._coding = params.get('coding', False)
        self._loopback = params.get('loopback', True)

        self._tx_buffer = []
        self._rx_buffer = []
        self._cb = None
        self._is_pulse_dial = False
        self._pulse_dial_count = 0
        self._rxd_stable = False  # rxd=Low
        self._rxd_counter = 0
        self._time_squelch = 0
        self._is_online = False
        self._is_enabled = False
        self._is_pulse_dial = False

        self._use_pulse_dial = True
        self._use_squelch = True
        self._use_rxd_observation = True

        self._status_out = 0
        self._status_act = 0
        self._status_dst = 0

        # init codec
        character_duration = (self._bytesize + 1.0 +
                              self._stopbits) / self._baudrate
        self._mc = txCode.BaudotMurrayCode(
            self._loopback,
            coding=self._coding,
            character_duration=character_duration)

        # init GPIOs
        pi.set_pad_strength(0, 8)

        pi.set_mode(self._pin_rxd, pigpio.INPUT)
        pi.set_pull_up_down(self._pin_rxd, pigpio.PUD_UP)
        pi.set_glitch_filter(self._pin_rxd, 1000)  # 1ms
        if self._pin_fsg_ns and self._pin_fsg_ns != self._pin_rxd:
            pi.set_mode(self._pin_fsg_ns, pigpio.INPUT)
            pi.set_pull_up_down(self._pin_fsg_ns, pigpio.PUD_UP)
            pi.set_glitch_filter(self._pin_fsg_ns, 1000)  # 1ms

        pi.set_mode(self._pin_txd, pigpio.OUTPUT)
        #pi.write(self._pin_txd, not self._inv_txd)
        pi.write(self._pin_txd, 1)
        pi.set_mode(self._pin_opt, pigpio.OUTPUT)
        pi.write(self._pin_opt, 0)
        pi.set_mode(self._pin_rel, pigpio.OUTPUT)  # relay for commutating
        pi.write(self._pin_rel, 0)  # pos polarity
        pi.set_mode(self._pin_dir, pigpio.OUTPUT)  # direction of comminication
        pi.write(self._pin_dir, 0)  # 1=transmitting

        if self._pin_status_r and self._pin_status_g:
            self._status_LED_r = LED_PWM(self._pin_status_r)
            self._status_LED_g = LED_PWM(self._pin_status_g)
            self.status('INIT')

        if self._pin_fsg_at:
            self._button_at = Button(self._pin_fsg_at,
                                     self._callback_button_at)
        if self._pin_fsg_st:
            self._button_st = Button(self._pin_fsg_st,
                                     self._callback_button_st)
        if self._pin_fsg_lt:
            self._button_lt = Button(self._pin_fsg_lt,
                                     self._callback_button_lt)

        self._set_enable(False)
        self._set_online(False)

        # init bit bongo serial read
        try:
            status = pi.bb_serial_read_close(
                self._pin_rxd
            )  # try to close if it is still open from last debug
        except:
            pass
        status = pi.bb_serial_read_open(self._pin_rxd, self._baudrate,
                                        self._bytesize)
        pi.bb_serial_invert(self._pin_rxd, self._inv_rxd)

        # init bit bongo serial write
        self.last_wid = None