Skip to content

Commit

Permalink
protocol.serialport add SerialPortProtocolSimulate
Browse files Browse the repository at this point in the history
  • Loading branch information
amaork committed Aug 7, 2017
1 parent e30db7f commit 937b8c9
Show file tree
Hide file tree
Showing 18 changed files with 157 additions and 57 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
32 changes: 32 additions & 0 deletions demos/serial_transaction_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import sys
import argparse
from ..protocol.serialport import SerialTransactionProtocol, SerialPort

if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-p", "--port", help="Serial port name", default="COM17")
parser.add_argument("-t", "--timeout", help="Serial port timeout", default=1)
parser.add_argument("-b", "--baudrate", help="Serial port baudrate", default=38400)
args = vars(parser.parse_args())

port = SerialPort(args.get("port"), args.get("baudrate"), args.get("timeout"))
serial_transaction = SerialTransactionProtocol(port.send, port.recv)

# Read test
result, data = serial_transaction.read(lambda x: print("Read:{}%".format(x)))
if not result:
print("Read error:{0:s}".format(data))
sys.exit(-1)

global_data, package_data = data[0], data[1]
print("Read success: global data size: {0:d}, package data size: {1:d}".format(len(global_data), len(package_data)))

# Write test
result, error = serial_transaction.write(global_data, package_data, lambda x: print("Write:{}%".format(x)))
if not result:
print("Write error:{0:s}".format(error))
sys.exit(-1)

print("Write success!")
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
157 changes: 125 additions & 32 deletions protocol/serialport.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# -*- coding: utf-8 -*-

from __future__ import print_function
import ctypes
import serial
from threading import Thread
from raspi_io import Serial as WebsocketSerial, RaspiSocketTError

from .crc16 import crc16
from ..core.datatype import BasicTypeLE


__all__ = ['SerialPort', 'SerialTransactionProtocol', 'ReadAckMsg']
__all__ = ['SerialPort', 'SerialTransactionProtocol', 'ReadAckMsg', 'SerialPortProtocolSimulate',
'SerialTransactionProtocolReadSimulate']


class ErrorCode(object):
Expand Down Expand Up @@ -168,33 +170,30 @@ class WriteAckMsg(BasicMsg):


class SerialTransactionProtocol(object):
def __init__(self, send, recv, verbose=False):
PAYLOAD_SIZE = 128

def __init__(self, send, recv):
""""Init a serial port transfer object
:param send: serial port send function
:param recv: serial port receive function
:param verbose: verbose message output
:return:
"""
assert hasattr(send, "__call__"), "{} send function is not callable".format(self.__class__.__name__)
assert hasattr(recv, "__call__"), "{} recv function is not callable".format(self.__class__.__name__)
self.__verbose = verbose
self.__send, self.__recv = send, recv

@staticmethod
def calc_package_size(data):
return 0 if not isinstance(data, str) else len(data) / WriteReqMsg.PAYLOAD_SIZE
return len(data) / SerialTransactionProtocol.PAYLOAD_SIZE

@staticmethod
def get_package_data(idx, data):
if not isinstance(idx, int) or not isinstance(data, str):
return ""

size = SerialTransactionProtocol.calc_package_size(data)
if not 0 <= idx < size:
return ""

return data[idx * WriteReqMsg.PAYLOAD_SIZE: (idx + 1) * WriteReqMsg.PAYLOAD_SIZE]
return data[idx * SerialTransactionProtocol.PAYLOAD_SIZE: (idx + 1) * SerialTransactionProtocol.PAYLOAD_SIZE]

def read(self, callback=None):
# Send r_init request
Expand All @@ -205,10 +204,6 @@ def read(self, callback=None):
# Get package size and global data
package_size, global_data = data[0], data[1]

# Verbose
if self.__verbose:
print("Read init success, package size:{0:d}".format(package_size))

# Read package data
package_data = ""
for package_index in range(package_size):
Expand All @@ -218,9 +213,6 @@ def read(self, callback=None):
else:
package_data += data

if self.__verbose:
print("Read data package[{0:03d}] success".format(package_index))

if callback and hasattr(callback, "__call__"):
callback((package_index + 1) / (package_size * 1.0) * 100)

Expand All @@ -241,19 +233,12 @@ def write(self, global_data, package_data, callback=None):
if not result:
return False, error

# Verbose
if self.__verbose:
print("Write init success, package size: {0:d}".format(package_size))

# Write all data
for package_index in range(package_size):
result, data = self.__w_data(package_index, self.get_package_data(package_index, package_data))
if not result:
return False, data

if self.__verbose:
print("Write data package[{0:03d}] success".format(package_index))

if callback and hasattr(callback, "__call__"):
callback((package_index + 1) / (package_size * 1.0) * 100)

Expand Down Expand Up @@ -295,10 +280,7 @@ def __r_init(self):

# Send read init request and get ack
result, data = self.__basic_transfer(req)
if not result or not isinstance(data, ReadAckMsg):
return result, data
else:
return True, (int(data.args), data.get_data_payload())
return (True, (int(data.args), data.get_data_payload())) if isinstance(data, ReadAckMsg) else (False, data)

def __r_data(self, package_index):
"""Read package_index specified package index
Expand All @@ -310,10 +292,7 @@ def __r_data(self, package_index):

# Send read init request and get ack
result, data = self.__basic_transfer(req)
if not result or not isinstance(data, ReadAckMsg):
return result, data
else:
return True, data.get_data_payload()
return (True, data.get_data_payload()) if isinstance(data, ReadAckMsg) else (False, data)

def __w_init(self, package_size, global_data):
"""Launch a write transfer section
Expand Down Expand Up @@ -365,6 +344,9 @@ def __str__(self):
def raw_port(self):
return self.__port

def close(self):
self.__port.close()

def flush(self):
self.__port.flushInput()
self.__port.flushOutput()
Expand Down Expand Up @@ -421,3 +403,114 @@ def recv(self, size):

except serial.SerialException, e:
return False, "Receive data exception: {0:s}".format(e)


class SerialPortProtocolSimulate(object):
def __init__(self, send, recv, error_handle=print):
assert hasattr(send, "__call__"), "{} send function is not callable".format(self.__class__.__name__)
assert hasattr(recv, "__call__"), "{} recv function is not callable".format(self.__class__.__name__)
self.__running = False
self.__sim_thread = Thread()
self.__handle = error_handle
self.__send, self.__recv = send, recv

def _get_request_size(self):
pass

def _check_request(self, req):
return False, "Unknown request"

def _get_req_handle(self, req):
pass

def _error_request(self, req):
pass

def __error_handle(self, error):
if hasattr(self.__handle, "__call__"):
self.__handle(error)

def __simulate(self):
while self.__running:
try:

# Wait request message from serial port
result, data = self.__recv(self._get_request_size())
if not result:
self.__error_handle("Receive request error:{0:s}".format(data))
continue

# Check request message
result, err_or_req = self._check_request(data)
if not result:
error = err_or_req
self.__error_handle("Check request error:{0:s}".format(error))
continue

# Process request and get ack
req = err_or_req
handle = self._get_req_handle(req)
if callable(handle):
ack = handle(req)
else:
ack = self._error_request(req)

# Ack peer
self.__send(ack)

except serial.SerialException as error:
self.__error_handle("SerialPort error:{0:s}".format(type(self).__name__, error))

def start(self):
if self.__running:
print("{} is running!".format(self.__class__.__name__))
return False

self.__running = True
self.__sim_thread = Thread(target=self.__simulate, name="{}".format(self.__class__.__name__))
self.__sim_thread.setDaemon(True)
print("{} start running".format(type(self).__name__))
self.__sim_thread.start()
return True

def stop(self):
self.__running = False
self.__sim_thread.join()
print("{} is stopped".format(self.__class__.__name__))


class SerialTransactionProtocolReadSimulate(SerialPortProtocolSimulate):
def __init__(self, send, recv, data, error_handle=print):
super(SerialTransactionProtocolReadSimulate, self).__init__(send, recv, error_handle)
self.__global_data, self.__config_data = data
self.__total_package = SerialTransactionProtocol.calc_package_size(self.__config_data)

def _get_request_size(self):
return ctypes.sizeof(ReadReqMsg)

def _check_request(self, data):
if not isinstance(data, str):
return False, "Request data type error!"

return ReadReqMsg(0, 0).init_and_check(data)

def _get_req_handle(self, req):
if not isinstance(req, ReadReqMsg):
return self._check_request

return {

ReadReqMsg.INIT_REQ: self.read_init,
ReadReqMsg.DATA_REQ: self.read_data,

}.get(req.req, self._error_request)

def _error_request(self, req):
return ""

def read_init(self, req):
return ReadAckMsg.create(req.req, self.__total_package, self.__global_data).cdata()

def read_data(self, req):
data = SerialTransactionProtocol.get_package_data(req.args, self.__config_data)
return ReadAckMsg.create(req.req, req.args, data).cdata()
25 changes: 0 additions & 25 deletions tests/stransfer_test.py

This file was deleted.

0 comments on commit 937b8c9

Please sign in to comment.