* modem_emu added
This commit is contained in:
parent
d58fc08526
commit
a845b34fbc
181
modem_emu.py
Executable file
181
modem_emu.py
Executable file
@ -0,0 +1,181 @@
|
||||
#!/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()
|
||||
Loading…
x
Reference in New Issue
Block a user