Prechádzať zdrojové kódy

[tools]add portgw test

balbekova 5 rokov pred
rodič
commit
ce44130c13

+ 1 - 0
tools/portgw/.gitignore

@@ -0,0 +1 @@
+*.pyc

+ 30 - 0
tools/portgw/debug.py

@@ -0,0 +1,30 @@
+import struct
+
+DEBUG = False
+
+class bcolors:
+    GREY = '\033[90m'
+    ORANGE = '\033[91m'
+    GREEN = '\033[92m'
+    YELLOW = '\033[93m'
+    BLUE = '\033[94m'
+    PURPLE = '\033[95m'
+    CYAN = '\033[96m'
+    WHITE = '\033[97m'
+    DEFAULT = '\033[99m'
+    ENDC = '\033[0m'
+    BOLD = '\033[1m'
+    UNDERLINE = '\033[4m'
+
+
+def print_data(name, data, length = None, color = bcolors.DEFAULT):
+    if not DEBUG: return
+    if data == None or not len(data): return
+    if length == None: length = len(data) 
+    print color + name,
+    for c in data[:length]: print "0x%02X"%(ord(c)),
+    print bcolors.ENDC
+
+def print_debug(str):
+    if not DEBUG: return
+    print str

+ 31 - 0
tools/portgw/portgw_base.py

@@ -0,0 +1,31 @@
+import struct
+from threading import RLock
+from transport import PortgwSerial
+from transport import PortgwTcp
+
+
+class PortgwBase(object):
+	def __init__(self, transport):
+		self.uart_lock = RLock()
+		self.tries = 1
+
+		self.open = transport.open
+		self.close = transport.close
+
+		self.write = transport.write
+		self.read = transport.read
+
+
+class PortgwBaseSerial(PortgwBase):
+	def __init__(self, _serial_port, _baudrate):
+		transport = PortgwSerial(_serial_port, _baudrate)
+		super(PortgwBaseSerial, self).__init__(transport)
+		# self.transport = PortgwSerial(_serial_port, _baudrate)
+
+
+class PortgwBaseTcp(PortgwBase):
+	def __init__(self, _ip, _port):
+		transport = PortgwTcp(_ip, _port)
+		super(PortgwBaseTcp, self).__init__(transport)
+		# self.transport = PortgwTcp(_ip, _port)
+		

+ 318 - 0
tools/portgw/portgw_test.py

@@ -0,0 +1,318 @@
+#!/usr/bin/python
+
+import sys, getopt, time
+import debug, json, settings
+from datetime import datetime
+from transport import PortgwSerial
+from transport import PortgwTcp
+
+
+def usage():
+	print "Usage:\r\n\
+	--ip=<address> \t\tIP adress to connect to\r\n\
+	--port=<number> \tPort number to connect to\r\n\
+	--serial=<device> \tSerial port to use\r\n\
+	--baud=<baudrate> \tbaudrate\r\n\
+	--bytesize=<number> \tbyte size in bits\r\n\
+	--parity=['N'|'O'|'E'] \tparity: none, odd, even\r\n\
+	--stopbits=<number> \tnumber of stop bits\r\n\
+	--all \t\t\tcheck all UART modes\r\n\
+	--help \t\t\tprint usage info\r\n\
+	--debug \t\tenable debug output"
+
+
+def print_bitrate(datalen, duration):
+	print "%.1f sec, %d bps" %(duration, datalen * 8 / duration)
+
+
+def test_src2dst(src, dst, data):
+	print "%s -> %s (%d bytes)" %(src.name, dst.name, len(data))
+
+	if not src.open():
+		print "%s open failed" %(src.name)
+		sys.exit()
+
+	if not dst.open():
+		print "%s open failed" %(dst.name)
+		sys.exit()
+
+	txdata = data
+	debug.print_debug("%s TX (%d bytes): %s" %(src.name, len(txdata), txdata[:10] + "..."))
+
+	timestamp = time.time()
+
+	res = src.write(txdata)
+	if res <= 0:
+		print "%s write fail" %(src.name)
+		sys.exit()
+
+	rxdata = dst.read(len(txdata), 1)
+	if res == None:
+		print "%s read fail" %(dst.name)
+		sys.exit()
+
+	debug.print_debug("%s RX (%d bytes): %s" %(dst.name, len(rxdata), rxdata[:10] + "..."))
+	if rxdata != txdata:
+		debug.print_data("TX:\n", txdata)
+		debug.print_data("RX:\n", rxdata)
+
+		print "Test failed:"
+		sys.exit()
+
+	print_bitrate(len(data), time.time() - timestamp)
+
+	print "OK\n"
+	dst.close()
+	src.close()
+
+
+def test_echo(src, dst, data):
+	print "%s -> %s -> %s -> %s (%d bytes)" %(src.name, dst.name, dst.name, src.name, len(data))
+
+	if not src.open():
+		print "TCP open failed"
+		sys.exit()
+
+	if not dst.open():
+		print "UART open failed"
+		sys.exit()
+
+	txdata = data
+	debug.print_debug("%s TX (%d bytes): %s" %(src.name, len(txdata), txdata[:10] + "..."))
+
+	timestamp = time.time()
+
+	res = src.write(txdata)
+	if res <= 0:
+		print "Write fail"
+		sys.exit()
+
+	echo = dst.read(len(txdata))
+	if res == None:
+		print "Read fail"
+		sys.exit()
+	
+	debug.print_debug("%s ECHO (%d bytes): %s" %(dst.name, len(echo), echo[:10] + "..."))
+	res = dst.write(echo)
+	if res <= 0:
+		print "Write fail"
+		sys.exit()
+
+	rxdata = src.read(len(echo))
+	if res == None:
+		print "Read fail"
+		sys.exit()
+	debug.print_debug("%s RX (%d bytes): %s" %(src.name, len(rxdata), rxdata[:10] + "..."))
+
+	if rxdata != txdata:
+		print "Fail"
+		sys.exit()
+
+	#Double data length (echo)
+	print_bitrate(len(data) * 2, time.time() - timestamp)	
+
+	print "OK\n"
+	src.close()
+	dst.close()
+
+
+def test_mult_requests(src, dst, data, duration):
+	print "%s -> %s -> %s -> %s (%d bytes, multi: %d sec)" %(src.name, dst.name, dst.name, src.name, 
+		len (data), duration)
+
+	if not src.open():
+		print "TCP open failed"
+		sys.exit()
+
+	if not dst.open():
+		print "UART open failed"
+		sys.exit()
+
+	txdata = data
+	req_count = 0
+	timestamp = time.time()
+
+	while time.time() - timestamp < duration:
+		print "\rDuration: %.1f/%.1f sec, request: %d" % (time.time() - timestamp, duration, req_count + 1),
+		sys.stdout.flush()
+		debug.print_debug("%s TX (%d bytes): %s" %(src.name, len(txdata), txdata[:10] + "..."))
+		res = src.write(txdata)
+		if res <= 0:
+			print "Write fail"
+			sys.exit()
+
+		echo = dst.read(len(txdata))
+		if res == None:
+			print "Read fail"
+			sys.exit()
+		
+		debug.print_debug("%s ECHO (%d bytes): %s" %(dst.name, len(echo), echo[:10] + "..."))
+		res = dst.write(echo)
+		if res <= 0:
+			print "Write fail"
+			sys.exit()
+
+		rxdata = src.read(len(echo))
+		if res == None:
+			print "Read fail"
+			sys.exit()
+		debug.print_debug("%s RX (%d bytes): %s\n" %(src.name, len(rxdata), rxdata[:10] + "..."))
+
+		if rxdata != txdata:
+			print "Fail"
+			sys.exit()
+
+		req_count += 1
+
+	print "\nTest duration: %d sec, %d requests completed" %(duration, req_count)
+	print "OK\n"
+	src.close()
+	dst.close()
+
+
+def test_suite(uart, tcp, ip, session, baudrate, bytesize, parity, stopbits):
+	#Test data
+	test_packet = "AABBCCDD"*10
+
+	#Configure hosts's UART
+	uart.close()
+	uart.baudrate = baudrate
+	uart.bytesize = bytesize
+	uart.parity = parity
+	uart.stopbits = stopbits
+	uart.open()
+
+	# Configure device's UART
+	if not settings.change(ip, session, baudrate, bytesize, parity, stopbits):
+		print "UART settings set fail"
+		sys.exit(2)
+	else:
+		print "Settings: %d %d%s%d" %(baudrate, bytesize, parity, stopbits)
+
+
+	# UART -> TCP
+	print "-"*10
+	test_src2dst(uart, tcp, test_packet)
+
+
+	# TCP -> UART
+	print "-"*10
+	test_src2dst(tcp, uart, test_packet)
+
+
+	# TCP echo: TCP -> UART -> UART -> TCP
+	print "-"*10
+	test_echo(tcp, uart, test_packet)
+
+
+	# UART echo: UART -> TCP -> TCP -> UART
+	print "-"*10
+	test_echo(uart, tcp, test_packet)
+
+
+	# TCP -> UART -> UART -> TCP (multiple requests)
+	print "-"*10
+	test_mult_requests(tcp, uart, "AABBCCDD"*16, 5)
+
+
+	# UART -> TCP -> TCP -> UART (multiple requests)
+	print "-"*10
+	test_mult_requests(uart, tcp, "AABBCCDD"*16, 5)
+
+
+def main():
+	check_all = False
+	ip = None
+	port = 1001
+	serial = '/dev/ttyUSB0'
+	baudrate = 115200
+	bytesize = 8
+	parity = 'N'
+	stopbits = 1
+
+	try:
+		opts, args = getopt.getopt(sys.argv[1:], "hs:i:p:b:z:y:t:da", \
+			["help", "serial=", "ip=", "port=", "baud=", "bytesize=",
+			"parity=", "stopbits=", "debug", "all"])
+	except getopt.GetoptError:
+			usage()
+			sys.exit(2)
+
+	for opt, arg in opts:
+			if opt in ("-h", "--help"):
+				usage()
+				sys.exit()
+			if opt in ("-s", "--serial"): 
+				serial = arg
+			if opt in ("-b", "--baud"): 
+				if (arg.isdigit()):
+					baudrate = int(arg)
+				else:
+					usage()
+					sys.exit()
+			if opt in ("-z", "--bytesize"): 
+				if (arg.isdigit() and arg in ('7', '8')):
+					bytesize = int(arg)
+				else:
+					print arg
+					usage()
+					sys.exit()
+			if opt in ("-y", "--parity"): 
+				if (arg in ('N', 'O', 'E')):
+					parity = arg
+				else:
+					usage()
+					sys.exit()
+			if opt in ("-t", "--stopbits"): 
+				if (arg in ('1', '2')):
+					stopbits = int(arg)
+				else:
+					usage()
+					sys.exit()
+			if opt in ("-i", "--ip"): 
+				ip = arg
+			if opt in ("-p", "--port"):
+				if (arg.isdigit()):
+					port = int(arg)
+			if opt in ("-d", "--debug"):
+				debug.DEBUG = True
+			if opt in ("-a", "--all"):
+				check_all = True
+
+	if ip == None:
+		usage()
+		sys.exit(2)
+
+	tcp = PortgwTcp(ip, port)
+	uart = PortgwSerial(serial, baudrate, bytesize, parity, stopbits)
+
+	report = []
+
+	session = settings.login(ip)
+	if session == None:
+		sys.exit(2)
+
+	if check_all:	
+		for baudrate in (1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200):
+			for bytesize in (7, 8):
+				for parity in ('N', 'O', 'E'):
+					#Skip unsupported modes
+					if bytesize == 7 and parity == 'N':
+						continue
+					if stopbits in (1, 2):
+						#Run tests
+						test_suite(uart, tcp, ip, session, baudrate, bytesize, parity, stopbits)
+						report.append(str(baudrate) + " " + str(bytesize) + parity + str(stopbits))
+	else:
+		test_suite(uart, tcp, ip, session, baudrate, bytesize, parity, stopbits)
+		report.append(str(baudrate) + " " + str(bytesize) + parity + str(stopbits))
+
+	print "Checked:"
+	for i in report:
+		print i
+
+	print "\rAll done"
+
+
+if __name__ == '__main__':
+	main()

+ 108 - 0
tools/portgw/settings.py

@@ -0,0 +1,108 @@
+import requests
+import json
+
+def prepare(settings):
+
+	if settings["dhcp"] == 1.000000000:
+		settings["dhcp"] = "on"
+	if settings["dhcp"] == 0:
+		settings["dhcp"] = "off"
+
+	if settings["pgw_en"] == True:
+		settings["pgw_en"] = "on"
+	elif settings["pgw_en"] == False:
+		settings["pgw_en"] = "off"
+
+	print settings
+
+	post_data = "&read_community=" 		+ settings["read_community"] + \
+		"&write_community=" 			+ settings["write_community"] + \
+		"&managerIP=" 					+ settings["managerIP"] + \
+		"&managerIP2=" 					+ settings["managerIP2"] + \
+		"&managerIP3=" 					+ settings["managerIP3"] + \
+		"&managerIP4=" 					+ settings["managerIP4"] + \
+		"&managerIP5=" 					+ settings["managerIP5"] + \
+		"&di1=" 						+ settings["di1"] + \
+		"&di_name1=" 					+ settings["di_name1"] + \
+		"&di2=" 						+ settings["di2"] + \
+		"&di_name2=" 					+ settings["di_name2"] + \
+		"&type_ts1=" 					+ str(settings["type_ts1"]) + \
+		"&type_ts2=" 					+ str(settings["type_ts2"]) + \
+		"&ipaddr=" 						+ settings["ipaddr"] + \
+		"&gw=" 							+ settings["gw"] + \
+		"&mask=" 						+ settings["mask"] + \
+		"&dhcp=" 						+ settings["dhcp"] + \
+		"&pgw_en=" 						+ settings["pgw_en"] + \
+		"&pgw_port=" 					+ settings["pgw_port"] + \
+		"&pgw_baud=" 					+ str(settings["pgw_baud"]) + \
+		"&pgw_par=" 					+ str(settings["pgw_par"]) + \
+		"&pgw_ndata=" 					+ str(settings["pgw_ndata"]) + \
+		"&pgw_nstop=" 					+ str(settings["pgw_nstop"]) + \
+		"&ntp=" 						+ settings["ntp"] + \
+		"&ntpservip=" 					+ settings["ntpservip"] + \
+		"&ups_cell_min=" 				+ settings["ups_cell_min"] + \
+		"&ups_cell_max=" 				+ settings["ups_cell_max"] + \
+		"&mainvolt_high=" 				+ settings["mainvolt_high"] + \
+		"&mainvolt_low=" 				+ settings["mainvolt_low"] + \
+		"&mainvolt_hist=" 				+ settings["mainvolt_hist"] + \
+		"&temp_high=" 					+ settings["temp_high"] + \
+		"&temp_low=" 					+ settings["temp_low"] + \
+		"&temp_hist=" 					+ settings["temp_hist"] + \
+		"&case_temp_high=" 				+ settings["case_temp_high"] + \
+		"&case_temp_low=" 				+ settings["case_temp_low"] + \
+		"&case_temp_hist=" 				+ settings["case_temp_hist"]
+
+	return post_data
+
+
+def get(ip, session):
+	r = session.get("http://" + ip + "/settings.cgi", cookies = session.cookies, timeout = 1)
+	
+	if r.status_code != 200:
+		return None
+	try:
+		return r.json()
+	except:
+		return None
+
+
+def post(ip, session, post_data):
+	r = session.post("http://" + ip + "/settings.cgi", cookies = session.cookies, data=post_data, timeout = 1)
+	if r.status_code != 200:
+		return False
+	
+	return True
+
+def login(ip):
+	s = requests.Session()
+	data = {"login":"admin", "password":"12345"}
+	r = s.post("http://" + ip + "/login.cgi", data)
+	if r.status_code != 200:
+		return None
+	
+	return s
+
+
+def change(ip, session, baudrate = None, bytesize = None, parity = None, stopbits = None, enable = True):
+	params = get(ip, session)
+	if params == None:
+		return False
+
+	#Enable by default
+	params["pgw_en"] = enable
+
+	params["pgw_baud"] = baudrate
+	params["pgw_ndata"] = bytesize
+
+	if parity == 'N':
+		params["pgw_par"] = "no"
+	if parity == 'E':
+		params["pgw_par"] = "ev"
+	if parity == 'O':
+		params["pgw_par"] = "od"
+
+	params["pgw_nstop"] = stopbits
+
+	post(ip, session, prepare(params))
+
+	return True

+ 92 - 0
tools/portgw/transport.py

@@ -0,0 +1,92 @@
+import crcmod, copy, struct, sys, os, fcntl
+from datetime import datetime
+from serial import *
+import socket
+import debug
+
+class PortgwSerial(object):
+	def __init__(self, _serial_port, _baudrate, _bytesize=8,
+			_parity='N', _stopbits=1):
+		self.serial_port = _serial_port
+		self.baudrate = _baudrate
+		self.bytesize = _bytesize
+		self.parity = _parity
+		self.stopbits = _stopbits
+		self.serial_resume()
+		self.name = "UART"
+
+	def serial_pause(self):
+		if self.serial != None:
+			self.serial.close()
+		self.serial = None
+
+	def serial_resume(self):
+		self.serial = serial_for_url(self.serial_port, self.baudrate, bytesize=self.bytesize, 
+			parity=self.parity, stopbits=self.stopbits, rtscts=False, xonxoff=False, timeout=0.12)
+		return self.serial != None
+
+	def open(self):
+		if self.serial == None:
+			return self.serial_resume()
+		else:
+			return True
+
+	def close(self):
+		self.serial_pause()
+
+	def read(self, nbytes, timeout = 1):
+		data = ''
+		self.serial.timeout = timeout
+		while len(data) < nbytes:
+			ret = self.serial.read(nbytes)
+			if len(ret) == 0:
+				break
+			data += ret
+		return data
+
+	def write(self, data):
+		self.serial.flushInput()
+		self.serial.flushOutput()
+		ret = self.serial.write(data)
+		# self.serial.flush()
+		return ret
+
+
+class PortgwTcp(object):
+	def __init__(self, _ip, _port):
+		self.ip = _ip
+		self.port = _port
+		self.name = "TCP"
+
+	def open(self):
+		self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+		try:
+			self.sock.connect((self.ip, self.port))
+			# fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
+		except socket.error, e:
+			print "\r\nConnection to %s:%s failed. Exit" %(self.ip, self.port)
+			return False
+		time.sleep(0.1)
+		return True
+
+	def close(self):
+		self.sock.close()
+
+	def read(self, nbytes, timeout = 1):
+		data = ''
+		self.sock.settimeout(timeout)
+		while len(data) < nbytes:
+			try:
+				ret = self.sock.recv(nbytes)
+			except socket.error, e:
+				err = e.args[0]
+				if err == 'timed out':
+					break
+			data += ret
+		return data
+
+	def write(self, data):
+		sent = self.sock.send(data)
+		if sent == 0:
+			raise RuntimeError("socket connection broken")
+		return sent

+ 166 - 0
tools/portgw_test.sh

@@ -0,0 +1,166 @@
+#!/bin/bash
+
+DEFPORT=1001
+DEFTTY=/dev/ttyUSB0
+DEFBAUD=115200
+
+TRANSPORT=${1}
+FILESIZE=${2}
+IP=${3}
+PORT=${4:-$DEFPORT}
+TTY=${5:-$DEFTTY}
+BAUD=${6:-$DEFBAUD}
+
+SRCFILE=/dev/shm/data.dump
+DSTFILE=/tmp/data.dump
+
+#Max size of supported UDP datagram size.
+#Higher size packets will be partially lost by application.
+MAXDGRAMMSIZE=512
+
+[[ -z $TRANSPORT ]] && { echo "No transport: [tcp|udp]"; exit 1; }
+[[ -z $IP ]] && { echo "No IP!"; exit 1; }
+[[ -z $FILESIZE ]] && { echo "No file size!"; exit 1; }
+
+
+trap abort INT
+
+
+function cleanup {
+    rm -rf $SRCFILE
+    rm -rf $DSTFILE
+    [[ -z $bg_proc ]] && exit 1
+    kill $bg_proc
+    wait $bg_proc 2>/dev/null
+    #kill $(jobs -pr)
+}
+
+function abort {
+    echo "Aborted!"
+    cleanup
+    exit 2
+}
+
+function setup {
+    echo "Transfer size: $FILESIZE"
+
+    #Check if port is available
+    [[ $TRANSPORT == "udp" ]] && NC_ARGS="-u"
+    nc -vz $NC_ARGS $IP $PORT    
+    [[ $? != 0 ]] && { echo "Port $PORT is not available"; cleanup; exit 1; }
+    #Wait UDP port ping
+    [[ $TRANSPORT == "udp" ]] && sleep 1
+
+    stty -F $TTY $BAUD # -icanon
+    dd if=/dev/urandom of=$SRCFILE bs=$FILESIZE count=1 2>&1 &>/dev/null
+    md5_sent=$(md5sum $SRCFILE | cut -d$' ' -f1)
+    echo "Out MD5: $md5_sent"
+}
+
+function check_transfer {
+    md5_rcvd=$(md5sum $DSTFILE | cut -d$' ' -f1)
+    echo -e " In MD5: $md5_rcvd"
+    echo "$(stat -c%s $DSTFILE)/$(stat -c%s $SRCFILE) bytes received"
+    echo "--------------------------------------------"
+    [[ $md5_sent != $md5_rcvd ]] && { echo -e "Test failed, transferred file MD5 missmatch!\r\n"; cleanup; exit 1; }
+    echo -e "Test OK\r\n"
+}
+
+function test_serial2tcp {
+    setup
+
+    socat -u tcp:$IP:$PORT $DSTFILE &
+    bg_proc=$!
+    [[ -z $bg_proc ]] && { echo "Socat not started!"; cleanup; exit 1; }
+
+    socat -u "SYSTEM:dd if=$SRCFILE bs=$FILESIZE count=1" $TTY,raw
+
+    #Wait data to be transferred
+    sleep 1
+
+    check_transfer
+    cleanup
+}
+
+function test_serial2udp {
+    setup
+
+    #Send initial request
+    echo "." | nc -u $IP $PORT > $DSTFILE &
+    bg_proc=$!
+    [[ -z $bg_proc ]] && { echo "Socat not started!"; cleanup; exit 1; }
+
+    #Wait initial request transferred
+    sleep 1
+
+    socat -u "SYSTEM:dd if=$SRCFILE bs=$FILESIZE count=1" $TTY,raw
+
+    #Wait data to be transferred
+    sleep 1
+
+    check_transfer
+    cleanup
+}
+
+function test_tcp2serial {
+    setup
+
+    socat -u $TTY,raw $DSTFILE &
+    bg_proc=$!
+    [[ -z $bg_proc ]] && { echo "Socat not started!"; cleanup; exit 1; }
+
+    #socat -u "SYSTEM:dd if=$SRCFILE bs=$FILESIZE count=1" tcp:$IP:$PORT
+    dd if=$SRCFILE | nc $IP $PORT
+
+    #Wait data to be transferred
+    sleep 1
+
+    check_transfer
+    cleanup
+}
+
+function test_udp2serial {
+    setup
+
+    socat -u $TTY,raw $DSTFILE &
+    bg_proc=$!
+    [[ -z $bg_proc ]] && { echo "Socat not started!"; cleanup; exit 1; }
+
+    #Split data to the $MAXDGRAMMSIZE size blocks
+    socat -u -b$MAXDGRAMMSIZE "SYSTEM:dd if=$SRCFILE" udp:$IP:$PORT
+
+    #Wait data to be transferred
+    sleep 1
+
+    check_transfer
+    cleanup
+}
+
+
+if [[ $TRANSPORT == "tcp" ]]
+then
+    # Serial -> TCP
+    echo -e "\r\nSerial->TCP"
+    echo "============================================"
+    test_serial2tcp
+
+    # TCP -> Serial
+    echo -e "\r\nTCP->Serial"
+    echo "============================================"
+    test_tcp2serial
+fi
+
+if [[ $TRANSPORT == "udp" ]]
+then
+    # Serial -> UDP
+    echo -e "\r\nSerial->UDP"
+    echo "============================================"
+    test_serial2udp
+
+    # UDP -> Serial
+    echo -e "\r\nUDP->Serial"
+    echo "============================================"
+    test_udp2serial
+fi
+
+exit 0