Пример #1
0
 def udp_echo(self, host, port, echo_delay, echo_wait, verbose=True):
     ser = self.myserial
     echo_host = '35.212.147.4'
     port = '3030'
     write_sock = '0'  # Use socket 0 for sending
     if self.udp_listen(port, 0, verbose=verbose):  # Open listen port
         aerisutils.print_log('Listening on port: ' + port)
     else:
         return False
     # Open UDP socket to the host for sending echo command
     rmutils.write(ser, 'AT+QICLOSE=0', delay=1,
                   verbose=verbose)  # Make sure no sockets open
     mycmd = 'AT+QIOPEN=1,0,\"UDP\",\"' + echo_host + '\",' + port + ',0,1'
     rmutils.write(
         ser, mycmd, delay=1,
         verbose=verbose)  # Create UDP socket connection as a client
     sostate = rmutils.write(ser, 'AT+QISTATE=1,0',
                             verbose=verbose)  # Check socket state
     if "UDP" not in sostate:  # Try one more time with a delay if not connected
         sostate = rmutils.write(ser,
                                 'AT+QISTATE=1,0',
                                 delay=1,
                                 verbose=verbose)  # Check socket state
     # Send data
     udppacket = str('{"delay":' + str(echo_delay * 1000) + ', "ip":"' +
                     self.my_ip + '","port":' + str(port) + '}')
     #udppacket = str('Echo test!')
     # print('UDP packet: ' + udppacket)
     mycmd = 'AT+QISEND=0,' + str(len(udppacket))
     rmutils.write(ser, mycmd, udppacket, delay=0,
                   verbose=verbose)  # Write udp packet
     rmutils.write(ser, 'AT+QISEND=0,0',
                   verbose=verbose)  # Check how much data sent
     aerisutils.print_log('Sent echo command: ' + udppacket)
     if echo_wait == 0:
         # True indicates we sent the echo
         return True
     else:
         echo_wait = round(echo_wait + echo_delay)
         vals = rmutils.wait_urc(
             ser,
             echo_wait,
             self.com_port,
             returnonreset=True,
             returnonvalue='OK'
         )  # Wait up to X seconds to confirm data sent
         #print('Return: ' + str(vals))
         vals = rmutils.wait_urc(
             ser,
             echo_wait,
             self.com_port,
             returnonreset=True,
             returnonvalue='+QIURC:'
         )  # Wait up to X seconds for UDP data to come in
         vals = super().parse_response(vals, '+QIURC:')
         print('Return: ' + str(vals))
         if len(vals) > 2 and int(vals[2]) == len(udppacket):
             return True
         else:
             return False
Пример #2
0
 def udp_echo(self, host, port, echo_delay, echo_wait, verbose=True):
     echo_host = '35.212.147.4'
     echo_port = '3030'
     listen_port = '3032'
     ser = self.myserial
     # Create a packet session in case there is not one
     self.create_packet_session()
     # Close socket if open
     rmutils.write(ser, 'AT#SL=1,0,' + listen_port + ',0', delay=1)
     rmutils.write(ser, 'AT#SH=1', delay=1)
     # Create UDP socket for sending and receiving
     mycmd = 'AT#SD=1,1,' + echo_port + ',"' + echo_host + '",0,' + listen_port + ',1,0,1'
     rmutils.write(ser, mycmd, delay=1)
     # Send our UDP packet
     udppacket = str(
         '{"delay":' + str(echo_delay * 1000) + ', "ip":' + self.my_ip 
         + ',"port":' + listen_port + '}' + chr(26))
     rmutils.write(ser, 'AT#SSEND=1', udppacket, delay=1)  # Sending packets to socket
     aerisutils.print_log('Sent Echo command to remote UDP server')
     # Wait for data
     if echo_wait > 0:
         echo_wait = round(echo_wait + echo_delay)
         # Wait for data to come in; handle case where we go to sleep
         rmutils.wait_urc(ser, echo_wait, self.com_port, returnonreset=True,
                          returnonvalue='APP RDY')
         # Try to read data
         rmutils.write(ser, 'AT#SRECV=1,1500,1', delay=1)
Пример #3
0
 def get_module_ip(self, response):
     if len(response) < len('+CGPADDR: 1,'):
         aerisutils.print_log('Module IP Not Found')
     else:
         values = response.split('\r\n')
         self.my_ip = values[1].split(',')[1]
         aerisutils.print_log('Module IP is ' + self.my_ip)
Пример #4
0
 def enable_psm(self, tau_time, atime, verbose=True):
     ser = self.myserial
     super().enable_psm(tau_time, atime, verbose)
     rmutils.write(ser, 'AT+QCFG="psm/urc",1',
                   verbose=verbose)  # Enable urc for PSM
     aerisutils.print_log(
         'PSM is enabled with TAU: {0} s and AT: {1} s'.format(
             str(tau_time), str(atime)))
Пример #5
0
def bytes_or_utf(b, want_bytes=False, verbose=False):
    aerisutils.print_log(
        f'Returning bytes: {want_bytes} from something that is bytes {isinstance(b, bytes)}',
        verbose)
    if want_bytes:
        return b
    else:
        return b.decode('utf-8')
Пример #6
0
 def udp_listen(self,
                listen_port,
                listen_wait,
                verbose=True,
                returnbytes=False):
     '''Starts listening for UDP packets.
     Parameters
     ----------
     listen_port : int
         The port on which to listen.
     listen_wait : int
         Greater than zero if this method should wait for that many seconds for received packets.
         If less than or equal to zero, this method will return a boolean type.
     verbose : bool, optional
     returnbytes : bool, optional
         If True, returns bytes, instead of a string.
     Returns
     -------
     s : bool
         False if a packet data session was not active, or if setting up the UDP socket failed.
         True if the modem successfully started listening for packets.
     m : str or bytes
         Any URCs that arrived while listening for packets.
     '''
     ser = self.myserial
     read_sock = '1'  # Use socket 1 for listen
     if self.create_packet_session(verbose=verbose):
         aerisutils.print_log('Packet session active: ' + self.my_ip)
     else:
         return False
     # Open UDP socket for listen
     mycmd = 'AT+QIOPEN=1,' + read_sock + ',"UDP SERVICE","127.0.0.1",0,' + str(
         listen_port) + ',1'
     rmutils.write(ser, mycmd, delay=1,
                   verbose=verbose)  # Create UDP socket connection
     sostate = rmutils.write(ser,
                             'AT+QISTATE=1,' + read_sock,
                             verbose=verbose)  # Check socket state
     if "UDP" not in sostate:  # Try one more time with a delay if not connected
         sostate = rmutils.write(ser,
                                 'AT+QISTATE=1,' + read_sock,
                                 delay=1,
                                 verbose=verbose)  # Check socket state
         if "UDP" not in sostate:
             return False
     # Wait for data
     if listen_wait > 0:
         return rmutils.wait_urc(
             ser,
             listen_wait,
             self.com_port,
             returnonreset=True,
             returnbytes=returnbytes
         )  # Wait up to X seconds for UDP data to come in
     return True
Пример #7
0
 def udp_listen(self, listen_wait, verbose):
     ser = self.myserial
     read_sock = '1'  # Use socket 1 for listen
     if self.create_packet_session():
         aerisutils.print_log('Packet session active: ' + self.my_ip)
     else:
         return False
     # Open UDP socket for listen
     rmutils.write(ser, 'AT#SLUDP=1,1,3030', delay=1)  # Starts listener
     rmutils.write(ser, 'AT#SS', delay=1)
     if listen_wait > 0:
         rmutils.wait_urc(ser, listen_wait, self.com_port, returnonreset=True)  # Wait up to X seconds for UDP data to come in
         rmutils.write(ser, 'AT#SS', delay=1)
     return True
Пример #8
0
 def udp_echo(self, host, port, echo_delay, echo_wait, verbose=True):
     ser = self.myserial
     echo_host = host
     listen_port = port
     udp_socket = 0
     # echo_host = '195.34.89.241' # ublox echo server
     # port = '7' # ublox echo server port
     # Make sure we have a packet session
     self.create_packet_session(verbose=verbose)
     # Close our read socket
     self.close_socket(udp_socket, verbose)
     # Create a UDP socket
     mycmd = 'AT+USOCR=17,' + str(listen_port)
     socket_id = (super().get_values_for_cmd(mycmd,'+USOCR:'))[0]
     #print('Socket ID = ' + str(socket_id))
     # Send data
     udppacket = str(
                 '{"delay":' + str(echo_delay * 1000) + ', "ip":"' 
                 + self.my_ip + '","port":' + str(listen_port) + '}')
     mycmd = 'AT+USOST=' + str(socket_id) + ',"' + echo_host + '",' + str(port) + ',' + str(len(udppacket))
     rmutils.write(ser, mycmd, udppacket, delay=0, verbose=verbose)  # Write udp packet
     aerisutils.print_log('Sent echo command: ' + udppacket, verbose)
     # Always wait long enough to verify packet sent
     vals = rmutils.wait_urc(ser, 5, self.com_port, returnonvalue='OK', verbose=verbose)
     #print('Return: ' + str(vals))
     if echo_wait == 0:
         # True indicates we sent the echo
         return True
     else:
         # Wait for data
         echo_wait = round(echo_wait + echo_delay)
         # vals = rmutils.wait_urc(ser, echo_wait, self.com_port, returnonreset=True,
                          # returnonvalue='APP RDY')  # Wait up to X seconds for UDP data to come in
         vals = rmutils.wait_urc(ser, echo_wait, self.com_port, returnonreset=True,
                          returnonvalue='+UUSORF:', verbose=verbose)
         #print('Return: ' + str(vals))
         mycmd = 'AT+USORF=0,' + str(len(udppacket))
         #vals = rmutils.write(ser, mycmd, verbose=verbose)  # Read from socket
         vals = (super().get_values_for_cmd(mycmd,'+USORF:'))
         #print('Return: ' + str(vals))
         if len(vals) > 3 and int(vals[3]) == len(udppacket):
             return True
         else:
             return False
Пример #9
0
 def udp_listen(self, listen_port, listen_wait, verbose=True):
     ser = self.myserial
     udp_socket = 0
     if self.create_packet_session(verbose=verbose):
         aerisutils.print_log('Packet session active: ' + self.my_ip)
     else:
         return False
     # Close our read socket
     self.close_socket(udp_socket, verbose)
     # Open UDP socket
     socket_id = (super().get_values_for_cmd('AT+USOCR=17','+USOCR:'))[0]
     print('Socket ID = ' + str(socket_id))
     # Listen on udp socket port
     mycmd = 'AT+USOLI=' + str(socket_id) + ',' + str(listen_port)
     val = rmutils.write(ser, mycmd, verbose=verbose)      
     # Wait for data up to X seconds
     if listen_wait > 0:
         rmutils.wait_urc(ser, listen_wait, self.com_port, returnonreset=True)
     return True
Пример #10
0
def test(ctx, timeout, delay):
    """Send UDP echo and wait for response
    \f

    """
    timeout = timeout * 60
    echo_host = '35.212.147.4'
    echo_port = 3030
    echo_delay = 1
    echo_wait = 4
    # Get ready to do some timing
    start_time = time.time()
    elapsed_time = 0
    aerisutils.print_log('Starting test for {0} seconds'.format(timeout))
    while elapsed_time < timeout:
        success = my_module.udp_echo(echo_host, echo_port, echo_delay, echo_wait, verbose=ctx.obj['verbose'])
        aerisutils.print_log('Success: ' + str(success))
        if not success:
            success = my_module.udp_echo(echo_host, echo_port, echo_delay, echo_wait, verbose=ctx.obj['verbose'])
            aerisutils.print_log('Retry success: ' + str(success))        
        time.sleep(delay - echo_delay - echo_wait)
        elapsed_time = time.time() - start_time
    # Do some cleanup tasks
    aerisutils.print_log('Finished test')
Пример #11
0
def parse_shoulder_tap(packet, imsi, verbose=False):
    '''Parses a "packet" into a shoulder-tap.
    Parameters
    ----------
    packet : bytes
        Binary representation of a single shoulder-tap packet.
    imsi : str
        The IMSI of this device.
    verbose : bool, optional
        True for verbose debugging output.
    Returns
    -------
    shoulder_tap : BaseShoulderTap
        The parsed shoulder-tap.
        May be None if there was a problem.'''
    # the UDP0 scheme is:
    # one STX character
    # two characters representing the shoulder-tap-type: "01" is UDP0
    # four characters representing the sequence number
    # two characters representing the length of the payload
    # X bytes of binary data
    # one ETX character
    aerisutils.print_log(
        'The entire packet is: <' + aerisutils.bytes_to_utf_or_hex(packet) +
        '>', verbose)
    # STX is ASCII value 2 / Unicode code point U+0002
    STX = 2
    # parse first character: it should be STX
    if packet[0] != STX:
        aerisutils.print_log('Error: first character was not STX',
                             verbose=True)
        return None
    # parse next two characters: they should be "01"
    message_type = packet[1:3]
    if message_type == b'01':
        return parse_udp0_packet(packet[3:], imsi, verbose=verbose)
    else:
        aerisutils.print_log(
            'Error: message type was not 01 for Udp0; it was ' +
            aerisutils.bytes_to_utf_or_hex(message_type),
            verbose=True)
        return None
Пример #12
0
def test(ctx, timeout, delay):
    """Send http request and wait for response
    \f

    """
    timeout = timeout * 60
    #http_host = 'httpbin.org'
    http_host = '35.212.147.4'
    http_port = 80
    # Get ready to do some timing
    start_time = time.time()
    elapsed_time = 0
    aerisutils.print_log('Starting test for {0} seconds'.format(timeout))
    while elapsed_time < timeout:
        response = my_module.http_get(http_host, http_port, verbose=ctx.obj['verbose'])
        if response:
            response = True
        aerisutils.print_log('Success: ' + str(response))
        time.sleep(delay)
        elapsed_time = time.time() - start_time
    # Do some cleanup tasks
    aerisutils.print_log('Finished test')
Пример #13
0
def test(ctx, timeout, cycletime, delay):
    """Test eDRX mode 
    \f

    """
    timeout = timeout * 60
    echo_host = '35.212.147.4'
    echo_port = 3030
    echo_delay = int(cycletime / 2)
    echo_wait = int(cycletime / 2) + 4
    # Enable eDRX
    my_module.enable_edrx(cycletime, verbose=ctx.obj['verbose'])
    # Get ready to do some timing
    start_time = time.time()
    elapsed_time = 0
    aerisutils.print_log('Starting test for {0} seconds'.format(timeout))
    while elapsed_time < timeout:
        success = my_module.udp_echo(echo_host, echo_port, echo_delay, echo_wait + cycletime, verbose=ctx.obj['verbose'])        
        aerisutils.print_log('Success: ' + str(success))
        time.sleep(delay - echo_delay - echo_wait)
        elapsed_time = time.time() - start_time
    # Do some cleanup tasks
    my_module.disable_psm(verbose=ctx.obj['verbose'])
    aerisutils.print_log('Finished test')
Пример #14
0
 def disable_psm(self, verbose):
     ser = self.myserial
     super().disable_psm(verbose)
     rmutils.write(ser, 'AT+QCFG="psm/urc",0',
                   verbose=verbose)  # Disable urc for PSM
     aerisutils.print_log('PSM and PSM/URC disabled')
Пример #15
0
def test(ctx, timeout, psmtau, psmat, delay):
    """Test PSM mode 
    \f

    """
    echo_host = '35.212.147.4'
    echo_port = 3030
    echo_delay = delay
    echo_wait = 4
    # Enable PSM
    my_module.enable_psm(psmtau, psmat, verbose=ctx.obj['verbose'])
    time.sleep(1.0) # Sleep to allow enable to complete
    # Make sure network allowed the configuration we asked for
    psm_settings = my_module.get_psm_info(ctx.obj['verbose'])
    if 'tau_network' not in psm_settings:
        exit()
    tau_network = int(psm_settings['tau_network'])
    if tau_network - psmtau > 120:
        my_module.disable_psm(verbose=ctx.obj['verbose'])
        aerisutils.print_log('Network settings not within tolerance.')
        return False
    aerisutils.print_log('Network tau: ' + str(tau_network))
    # Get ready to do some timing
    start_time = time.time()
    elapsed_time = 0
    aerisutils.print_log('Starting test for {0} seconds'.format(timeout))
    while elapsed_time < timeout:
        #my_module.udp_echo(delay, 4, verbose=ctx.obj['verbose'])
        success = my_module.udp_echo(echo_host, echo_port, echo_delay, echo_wait, verbose=ctx.obj['verbose'])        
        aerisutils.print_log('Success: ' + str(success))
        rmutils.wait_urc(my_module.myserial, timeout, my_module.com_port, returnonreset=True, returnonvalue='APP RDY',
                         verbose=ctx.obj['verbose'])  # Wait up to X seconds for app rdy
        time.sleep(5.0) # Sleep in case it helps telit be able to connect
        my_module.init_serial(ctx.obj['comPort'], ctx.obj['apn'], verbose=ctx.obj['verbose'])
        rmutils.write(my_module.myserial, 'ATE0', verbose=ctx.obj['verbose'])  # Turn off echo
        aerisutils.print_log('Connection state: ' + str(my_module.get_packet_info(verbose=ctx.obj['verbose'])))
        elapsed_time = time.time() - start_time
    # Do some cleanup tasks
    my_module.disable_psm(verbose=ctx.obj['verbose'])
    aerisutils.print_log('Finished test')
Пример #16
0
    def udp_urcs_to_payloads(self, urcs, verbose=False):
        '''Parses a string of URCs representing UDP packet deliveries into a list of payloads, one per packet.

        Parameters
        ----------
        urcs : bytes
            The unsolicited result codes as output from e.g. udp_listen
            When delivered to a connectID that is serving a service of "UDP SERVICE," the Quectel BG96 outputs these URCs as "+QIURC: "recv",<connectID>,<currentrecvlength>,"<remote IP address>",<remoteport><CR><LF><data>
        verbose : bool, optional
            True to enable verbose/debugging output. Unrecognized URCs will be logged regardless of this value.
        Returns
        -------
        list
            An iterable of payloads, each a bytes object.
        '''
        # state machine:
        # (initial) -> (receive: +QIURC: "recv") -> (parse <connectID>,<currentrecvlength>,"remote ip",<remoteport><CR><LF>) -> read <currentrecvlength> bytes -> (initial)
        # (initial) -> (receive: +) -> (read rest of line, output as "unexpected URC") -> (initial)
        CHAR_CR = 13
        CHAR_LF = 10
        URC_HEAD = b'+QIURC: "recv",'
        urc_regex = re.compile(
            rb'\+QIURC: "recv",(?P<connectID>\d+),(?P<currentrecvlength>\d+),"(?P<remoteIP>[^"]+)",(?P<remotePort>\d+)'
        )
        payloads = []
        current_input = urcs
        while len(current_input) > 0:
            aerisutils.print_log(
                'Remaining input: ' +
                aerisutils.bytes_to_utf_or_hex(current_input), verbose)
            head = current_input[:len(URC_HEAD)]
            if head == URC_HEAD:
                # find the next carriage return
                next_carriage_return_index = current_input.find(b'\x0D')
                if next_carriage_return_index == -1:
                    aerisutils.print_log(
                        'Error: no carriage returns after an URC')
                parse_result = urc_regex.search(
                    current_input[:next_carriage_return_index])
                aerisutils.print_log(
                    'QIURC parse result: ' + str(parse_result), verbose)
                if not parse_result:
                    aerisutils.print_log('Error: failed to parse QIURC',
                                         verbose=True)
                connection_id = parse_result.group('connectID')

                aerisutils.print_log(
                    'Found connection ID: ' +
                    aerisutils.bytes_to_utf_or_hex(connection_id), verbose)
                length = parse_result.group('currentrecvlength')

                aerisutils.print_log(
                    'Found length of received data: ' +
                    aerisutils.bytes_to_utf_or_hex(length), verbose)
                remote_ip = parse_result.group('remoteIP')
                aerisutils.print_log(
                    'Found remote IP: ' +
                    aerisutils.bytes_to_utf_or_hex(remote_ip), verbose)
                remote_port = parse_result.group('remotePort')
                aerisutils.print_log(
                    'Found remote port: ' +
                    aerisutils.bytes_to_utf_or_hex(remote_port), verbose)
                # advance to the carriage return
                current_input = current_input[next_carriage_return_index:]

                # consume the CRLF
                if not (current_input[0] == CHAR_CR
                        and current_input[1] == CHAR_LF):
                    aerisutils.print_log(
                        'Sanity: the two bytes after the length were not a CRLF'
                    )
                current_input = current_input[2:]
                # consume the next number of bytes the URC said we would get, and advance that many
                payload = current_input[:int(length)]
                extracted_payload_length = len(payload)
                current_input = current_input[int(length):]
                if extracted_payload_length != int(length):
                    aerisutils.print_log(
                        f'Sanity: the packet extracted from the buffer was not {length} bytes long, it was {extracted_payload_length} bytes long. Ignoring packet.'
                    )
                    continue
                payloads.append(payload)
                aerisutils.print_log(
                    'Found packet: ' + aerisutils.bytes_to_utf_or_hex(payload),
                    verbose)
                # consume the trailing CRLF
                if not (current_input[0] == CHAR_CR
                        and current_input[1] == CHAR_LF):
                    aerisutils.print_log(
                        'Sanity: the two characters after the payload were not a CRLF'
                    )
                current_input = current_input[2:]
            else:
                # this is not the URC we expected
                # consume to the next newline, output as a warning or whatever, and try again
                newline_index = current_input.find(b'\n')
                if newline_index == -1:
                    aerisutils.print_log(
                        'Warning: no newline at end of unexpected URC: <<' +
                        aerisutils.bytes_to_utf_or_hex(current_input) + '>>')
                    # consume the rest of the input
                    current_input = []
                else:
                    unexpected_urc = current_input[:newline_index]
                    # this might be a blank line, i.e., just a CRLF
                    if unexpected_urc != b'\x0D':
                        aerisutils.print_log(
                            'Warning: found unexpected URC: <<' +
                            aerisutils.bytes_to_utf_or_hex(unexpected_urc) +
                            '>>',
                            verbose=True)
                    current_input = current_input[newline_index + 1:]
        return payloads
Пример #17
0
def parse_udp0_packet(packet, imsi, verbose=False):
    '''Parses (most of) a Udp0 shoulder-tap packet into a Udp0ShoulderTap.
    Parameters
    ----------
    packet : bytes
        The portion of the packet after the first three bytes, i.e., starting at the sequence number.
    imsi : str
        The IMSI of this device.
    verbose : bool, optional
        True for verbose output.
    Returns
    -------
    Udp0ShoulderTap or None if there was a problem.'''
    ETX = b'\x03'
    sequence_hex = packet[:4]
    # length check: sequence_hex should be 4 bytes long
    if len(sequence_hex) != 4:
        aerisutils.print_log(
            f'Error: did not get enough sequence number bytes; expected 4, got {len(sequence_hex)}',
            verbose=True)
        return None
    aerisutils.print_log(f'Sequence number binary: {sequence_hex}',
                         verbose=verbose)
    try:
        sequence_decimal = int(sequence_hex, base=16)
    except ValueError:
        aerisutils.print_log('Error: Sequence number was not hexadecimal',
                             verbose=True)
        return None

    payload_length_hex = packet[4:6]
    aerisutils.print_log(f'Payload length in hex: {payload_length_hex}',
                         verbose=verbose)
    # Length check: payload_length_check should be 2 bytes
    if len(payload_length_hex) != 2:
        aerisutils.print_log(
            f'Error: did not get enough payload length bytes; expected 2, got {len(payload_length_hex)}',
            verbose=True)
        return None
    try:
        payload_length_decimal = int(payload_length_hex, base=16)
    except ValueError:
        aerisutils.print_log('Error: payload length was not hexadecimal',
                             verbose=True)
        return None

    payload = packet[6:6 + payload_length_decimal]
    if len(payload) != payload_length_decimal:
        aerisutils.print_log(
            'Error: extracted payload length was not expected.', True)
        return None
    if len(payload) == 0:
        payload = None

    final_character = packet[6 + payload_length_decimal:7 +
                             payload_length_decimal]
    if final_character != ETX:
        aerisutils.print_log(
            f'Error: byte after the payload was not an ETX; it was (binary) {final_character}',
            verbose=True)
        return None

    return shoulder_tap.Udp0ShoulderTap(payload, sequence_decimal, imsi)
Пример #18
0
def wait_urc(ser,
             timeout,
             com_port,
             returnonreset=False,
             returnonvalue=False,
             verbose=True,
             returnbytes=False):
    '''Wait for unsolicited result codes from the module.
    Parameters
    ----------
    ser : serial port object
        The serial port the module is communicating on.
    timeout : int
        How many seconds to wait
    com_port : int
        The com port associated with the module
    returnonreset : bool, optional
        If truthy, this method will return as soon as there is a problem. Default: False.
    returnonvalue : any, optional
        If truthy, this function will return once this value is found on a line of output. Default: False.
    verbose : bool, optional
        True to print verbose output.
    returnbytes : bool, optional
        True to return a bytes object. Otherwise, tries to return a string decoded from UTF-8. If decoding any URC to UTF-8 fails, the returned string will be all of the preivous, successfully-decoded URCs. Default: False.
    Returns
    ------
    Either a bytes or a string, depending on the returnbytes parameter.
    '''

    mybytes = bytearray()
    myfinalout = None
    if returnbytes:
        myfinalout = b''
    else:
        myfinalout = ''
    start_time = time.time()
    elapsed_time = 0
    aerisutils.print_log(
        'Starting to wait up to {0}s for URC; returning bytes: {1}'.format(
            timeout, returnbytes), verbose)
    while elapsed_time < timeout:
        try:
            while ser.inWaiting() > 0:
                mybyte = ser.read()[0]
                mybytes.append(mybyte)
                if mybyte == 10:  # Newline
                    if returnbytes:
                        oneline = mybytes
                        myfinalout = myfinalout + mybytes
                        aerisutils.print_log(
                            "<< " +
                            aerisutils.bytes_to_utf_or_hex(oneline.strip()),
                            verbose)
                    else:
                        try:
                            oneline = mybytes.decode("utf-8")
                        except UnicodeDecodeError as e:
                            aerisutils.print_log('Error in wait_urc')
                            return myfinalout
                        myfinalout = myfinalout + oneline
                        aerisutils.print_log("<< " + oneline.strip(), verbose)
                    if returnonvalue:
                        if oneline.find(returnonvalue) > -1:
                            return myfinalout
                    mybytes = bytearray()
        except IOError:
            aerisutils.print_log('Exception while waiting for URC.', verbose)
            ser.close()
            find_serial(com_port,
                        verbose=True,
                        timeout=(timeout - elapsed_time))
            if returnonreset:
                return myfinalout
            else:
                ser.open()
        time.sleep(0.5)
        elapsed_time = time.time() - start_time
    aerisutils.print_log('Finished waiting for URC.', verbose)
    return myfinalout