#!/usr/bin/env python3 import sys import serial import re import socket import codecs import threading import queue from time import sleep class Socket: def __init__(self, modem_emu, socket_id, port): self.modem_emu = modem_emu self.socket_id = socket_id self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.settimeout(1) self.sock.bind(('', port)) self._stop_event = threading.Event() self.receiver_thread = threading.Thread(target=self.receiver_t) self.receiver_thread.start() self.incoming = queue.Queue() def receiver_t(self): while True: try: data, src = self.sock.recvfrom(512) except socket.timeout: data, src = None, None if src is not None: src_ip, src_port = src sleep(1.5) print('#### received message from {}:{}: {}'.format( src_ip, src_port, data)) self.incoming.put((self.socket_id, src_ip, src_port, data)) self.modem_emu.urcs.put((self.socket_id, len(data))) if self._stop_event.is_set(): break def close(self): self._stop_event.set() self.receiver_thread.join() self.sock.close() def send(self, message, remote_ip, remote_port): self.sock.sendto(message, (remote_ip, remote_port)) class ModemEmu: def __init__(self, serial_dev): self.ser = serial.Serial(serial_dev, 9600) self.next_socket_id = 100 self.socket_dct = {} self.urcs = queue.Queue() self.serial_lock = threading.Lock() self.at_cmd_thread = threading.Thread(target=self.at_cmd_t) self.urc_thread = threading.Thread(target=self.urc_t) def get_next_socket_id(self): ret = self.next_socket_id self.next_socket_id += 1 return ret def at(self, line, match): print('cmd=AT') self.ser.write(b'OK\r\n') def at_nrb(self, line, match): print('cmd=AT+NRB') for sid in self.socket_dct: self.socket_dct[sid].close() self.socket_dct.clear() self.next_socket_id = 100 self.ser.write(b'OK\r\n') def at_nsocr(self, line, match): listen_port = int(match.group(1)) receive_control = int(match.group(2)) print('cmd=AT+NSOCR; listen_port={}; receive_control={}'.format( listen_port, receive_control)) socket_id = self.get_next_socket_id() sock = Socket(self, socket_id, listen_port) self.socket_dct[socket_id] = sock self.ser.write(bytes('{}\r\n'.format(socket_id), 'ASCII')) self.ser.write(b'OK\r\n') def at_nsocl(self, line, match): socket_id = int(match.group(1)) print('cmd=AT+NSOCL; socket={}'.format(socket_id)) try: sock = self.socket_dct.pop(socket_id) except KeyError: print('at_nsocl: unknown socket') else: sock.close() self.ser.write(b'OK\r\n') def at_nsost(self, line, match): socket_id = int(match.group(1)) remote_ip = match.group(2) remote_port = int(match.group(3)) length = int(match.group(4)) data = match.group(5) print('cmd=AT+NSOST; socket={}; remote_ip={}; remote_port={}; length={}; ' 'data={}'.format(socket_id, remote_ip, remote_port, length, data)) try: sock = self.socket_dct[socket_id] except KeyError: print('at_nsost: unknown socket') else: message = codecs.decode(data, 'hex') sock.send(message, remote_ip, remote_port) sent_length = length self.ser.write(bytes('{},{}\r\n'.format(socket_id, sent_length), 'ASCII')) self.ser.write(b'OK\r\n') def at_nsorf(self, line, match): socket_id = int(match.group(1)) req_length = int(match.group(2)) print('cmd=AT+NSORF; socket={}; req_length={}'.format(socket_id, req_length)) try: sock = self.socket_dct[socket_id] except KeyError: print('at_nsorf: unknown socket') self.ser.write(b'ERROR\r\n') else: socket_id_2, src_ip, src_port, data = sock.incoming.get() assert socket_id == socket_id_2 assert req_length == len(data) remaining_length = 0 resp = '{},{},{},{},{},{}\r\n'.format( socket_id, src_ip, src_port, len(data), codecs.encode(data, 'hex').decode('ASCII'), remaining_length) self.ser.write(bytes(resp, 'ASCII')) self.ser.write(b'OK\r\n') def run(self): self.at_cmd_thread.start() self.urc_thread.start() def at_cmd_t(self): while True: line = self.ser.readline() self.serial_lock.acquire() line = line.strip() print(line) lst = [ (b'AT$', self.at), (b'AT\+NRB$', self.at_nrb), (b'AT\+NSOCR=DGRAM,17,(\d+),([0-1])', self.at_nsocr), (b'AT\+NSOCL=(\d+)', self.at_nsocl), (b'AT\+NSOST=(\d+),(\d+\.\d+\.\d+\.\d+),(\d+),(\d+),([0-9a-fA-F]+)', self.at_nsost), (b'AT\+NSORF=(\d+),(\d+)', self.at_nsorf), ] for regex, action in lst: m = re.match(regex, line) if m: action(line, m) break else: self.ser.write(b'ERROR\r\n') print("") self.serial_lock.release() def urc_t(self): while True: urc = self.urcs.get() socket_id, length = urc msg = '+NSONMI:{},{}\r\n'.format(socket_id, length) self.serial_lock.acquire() self.ser.write(bytes(msg, encoding='ASCII')) self.serial_lock.release() if len(sys.argv) != 2: print('Usage: {} device'.format(sys.argv[0])) sys.exit(1) serial_dev = sys.argv[1] modem_emu = ModemEmu(serial_dev) modem_emu.run()