2017-12-13 26 views
0

주요 유스 케이스가 CLI를 통해 상호 작용하여 직렬로 바이트 패킷을 보내도록 지시하는 파이썬 프로그램이 있습니다. 직렬 타겟은 특정 명령 프로토콜을 준수합니다. python 프로그램은 CLI (명령을 보내기위한 특정 명령, 명령에 대한 인수 등)에 대한 사용자 입력을 기반으로이 프로토콜을 따르는 패킷을 작성합니다.스크립트에서 사용되는 디커플링 클래스에 대한 제안이 필요합니다.

이 모듈은 세 가지 클래스로 구성됩니다. 하나는 가능한 각 명령에 대한 고유 식별자를 만드는 열거 형이고, 다른 하나는 cmd 모듈을 하위 클래스로 구분하여 사용자에게 CLI 인터페이스를 구현하는 클래스입니다 (이 클래스도 입력 입력 소거를 인수로 사용합니다) 마지막으로 원하는 명령과 인수를 받아서 직렬로 전송할 패킷을 빌드하는 하나의 클래스

내가 갖고있는 문제는 이러한 클래스가 꽤 결합하고 있다는 것입니다. 이상적으로는 Master_Comm 클래스를 독립적으로 사용하여 다른 모듈에서 액세스하여 다른 출처 (예 : 스크립트 파일 파서)의 패킷을 보낼 수 있기를 바랬습니다. 그대로 Serial_Interfacesendcommand 방법에 액세스 할 수 Master_Comm의 예뿐만 아니라 여러 장소를 수행해야 할 수 있습니다 구현 입력 위생을 (가지고 있습니다.

이 더 나은 조직에 어떤 제안? 프로그램이 성장, 특히 (아마도 구현 명령 수백).

import serial 
from cmd import Cmd 
from enum import Enum, unique 

@unique 
class Command_Names(Enum): 
    CMD1 = 1 
    CMD2 = 2 

class Serial_Interface(Cmd): 
    def __init__(self, port, baud,): 
     Cmd.__init__(self) 
     self.slave_comm = Master_Comm(port=port, baud=baud) 
     # setup stuff 

    def do_cmd1(self, args): 
     try: 
      assert 0 <= int(args) <= 25, "Argument out of 0-25 range" 
      self.slave_comm.sendcommand(Command_Names.CMD1, args) 
     except (AssertionError) as e: 
      print(e) 

    def do_cmd2(self, args): 
     try: 
      # No args for cmd2, so don't check anything 
      self.slave_comm.sendcommand(Command_Names.CMD2, args) 
     except (AssertionError) as e: 
      print(e) 


class Master_Comm(object): 
    _SLAVE_COMMANDS = {Command_Names.CMD1:   (b'\x10', b'\x06', b'\x06'), 
         Command_Names.CMD2:   (b'\x10', b'\x07', b'\x07')} 

    _SOURCE_ID = b'\xF0' 
    _SEQ_NUM = b'\x00' 

    def __init__(self, port, baud): 
     self.ser = serial.Serial(port=None, 
           baudrate=int(baud) 
           ) 
     self.ser.port = port 

    def open_serial(self): 
     # do stuff 

    def close_serial(self): 
     # do stuff 

    def sendcommand(self, command, args): 
     try: 
      txpacket = bytearray() 
      txpacket.extend(self._SOURCE_ID) 
      txpacket.extend(self._SEQ_NUM) 
      txpacket.extend(self._SLAVE_COMMANDS[command][0]) 
      txpacket.extend(self._SLAVE_COMMANDS[command][1]) 
      txpacket.extend(self._SLAVE_COMMANDS[command][2]) 
      self.ser.write(tx_bytes) 
     except Exception as e: 
      print(e) 
+0

확실히 asyncio를 확인하십시오. – GRAYgoose124

답변

0

당신은 __init__() 생성자에 인수로 전달하여 Master_Comm 클래스에 하드 코드 명령을 분리 할 수 ​​있습니다. 아래는 CMDS라는 새 사전을 만들고 사용하는이의 간단한 구현입니다 따로 정의 됨.

이 테이블은 인스턴스가 생성 될 때 Master_Comm 클래스에 인수로 전달 된 다음 SerialInterface 클래스에 인수로 전달됩니다 (자체 생성 대신).

이 아이디어는 CMDS 테이블의 형식을 변경하여 명령에 대한 추가 정보를 포함하도록하고 이후에도 SerialInterface 클래스의 구현에서 사용합니다 (예 : 각 튜플과 관련된 바이트의 튜플의 길이).

참고로 클래스 이름을 PEP 8 - Style Guide for Python Code의 이름 지정 권장 사항을 따르도록 변경했습니다.

import serial 
from cmd import Cmd 
from enum import Enum, unique 

class SerialInterface(Cmd): 
    def __init__(self, mastercomm): 
     Cmd.__init__(self) 
     self.slave_comm = mastercomm 
     # setup stuff 

    def do_cmd1(self, args): 
     try: 
      assert 0 <= int(args) <= 25, "Argument out of 0-25 range" 
      self.slave_comm.sendcommand(CommandNames.CMD1, args) 
     except (AssertionError) as e: 
      print(e) 

    def do_cmd2(self, args): 
     try: 
      # No args for cmd2, so don't check anything 
      self.slave_comm.sendcommand(CommandNames.CMD2, args) 
     except (AssertionError) as e: 
      print(e) 


class MasterComm: 
    """ Customized serial communications class for communicating with serial 
     port using the serial module and commands defined by the table "cmds". 
    """ 
    def __init__(self, port, baud, cmds): 
     self.ser = serial.Serial(port=None, 
           baudrate=int(baud),) 
     self.ser.port = port 
     self.source_id = cmds['source_id'] 
     self.seq_num = cmds['seq_num'] 
     self.slave_commands = cmds['slave_commands'] 

    def sendcommand(self, command, args): 
     try: 
      txpacket = bytearray() 
      txpacket.extend(self.source_id) 
      txpacket.extend(self.seq_num) 
      txpacket.extend(self.slave_commands[command][0]) 
      txpacket.extend(self.slave_commands[command][1]) 
      txpacket.extend(self.slave_commands[command][2]) 
      self.ser.write(txpacket) 
     except Exception as e: 
      print(e) 


@unique 
class CommandNames(Enum): 
    CMD1 = 1 
    CMD2 = 2 

CMDS = { 
    'source_id': b'\xF0', 
    'seq_num': b'\x00', 
    'slave_commands' : {CommandNames.CMD1: (b'\x10', b'\x06', b'\x06'), 
         CommandNames.CMD2: (b'\x10', b'\x07', b'\x07')} 
} 

mastercomm = MasterComm(0x03b2, 8192, CMDS) 
serialinterface = SerialInterface(mastercomm) 
serialinterface.cmdloop()